Skip to content

How to fix "Updating failed" and "Publishing failed" in the WordPress editor

The block editor saves through the site's REST API. "Updating failed" means the answer to that request was not the JSON the editor expects. Nothing already saved is lost. Look at what came back instead of JSON, and the fix follows from it.

By
WP Ministry
Published
Tested on
WordPress 7.1.3, PHP 8.3.35

In short

  • Nothing already saved is lost. The change on your screen is not saved yet, so copy it before you reload.
  • The editor saves through the REST API, at /wp-json/. The message means the answer was not JSON.
  • Open /wp-json/ in a browser tab. A 404 there means the rewrite rules are missing.
  • The browser's Network panel shows the failed request's status and what came back. That tells the causes apart.
  • A 403 comes from a security plugin or a firewall, and the rule is theirs to change.

The block editor saves by sending your changes to the site's REST API, at an address that begins /wp-json/, and it expects the answer in a data format called JSON. "Updating failed." or "Publishing failed." means the save did not go through. When the notice ends "The response is not a valid JSON response.", something did answer, but not with JSON: a 404 page, a firewall's block page, or the right answer with a PHP message printed in front of it.

Nothing that was already saved is lost. The change on your screen is not saved yet, and it exists only in that browser tab.

Keep what you wrote

Do not reload the page or close the tab. Click the three dots in the editor's top toolbar, then choose "Copy all blocks". The editor answers "All content copied." Paste it into a text file on your computer, and paste it back into the post once saving works.

Find out what came back

Three checks, quickest first.

Open the REST API yourself. In a new tab, go to https://example.com/wp-json/, with your own domain. A screen of text that begins with { is JSON, and the address works. A 404 page means the first fix. If your permalinks are set to Plain, the address is https://example.com/?rest_route=/ instead.

Ask Site Health. Go to Tools, then Site Health. "The REST API is available" among the passed tests means the server reached its own API. "The REST API encountered an error" or "The REST API encountered an unexpected result" opens to show the address it tried and the response it got. The server makes this test on itself, so it can pass while requests from your browser still fail.

Read the failed request. Open your browser's developer tools and click the Network tab. It records only while it is open, so save again. Click the request that failed, read its status, then open its Response tab.

What the request showsUse
Status 404 and a "not found" pageThe first fix
Text ahead of the first { that names a .php file and a lineThe second fix
An address that differs from the one in your address barThe third fix
Status 403, or a page that says the request was blockedThe fourth fix
Anything elseThe fifth fix

If the notice ends "Could not get a valid response from the server." instead, the browser got no answer at all. Start with the third fix.

Where it goes wrong

A page request passes through each of these in turn. This one comes from WordPress itself.

  1. Browser
  2. DNS
  3. HTTPS
  4. CDN or firewall
  5. Web server
  6. PHP
  7. WordPress (this error comes from here)
  8. Database and files

What causes it

  • The REST API address answers 404

    Common

    With pretty permalinks the editor saves to an address that begins /wp-json/. That address exists only inside WordPress, so it depends on the rewrite rules in .htaccess. When they are missing, the web server answers with its own 404 page.

    Fix: Get /wp-json/ answering again

  • A PHP message is printed in front of the answer

    Sometimes

    A warning or notice printed into the response comes out ahead of the JSON, and the two together are not JSON. WordPress hides such messages from the editor's requests, so one that gets through was printed before WordPress had loaded or by code that turns display back on.

    Fix: Stop PHP printing messages into the answer, or Switch off the plugin that breaks the answer

  • The site's address settings do not match the address in your browser

    Sometimes

    The editor sends its requests to an address built from the Site Address setting. When that is not the address you are working at, http in place of https or another form of the domain, the request goes somewhere other than the page it came from. A browser blocks an http request made from an https page.

    Fix: Make the site's address match the one you work at

  • A security plugin or a firewall refuses the request

    Sometimes

    A firewall compares each request with general patterns of attack. A post that contains HTML or code can match one by mistake, and the request is refused before WordPress can answer it.

    Fix: Find what refused the request and have the rule changed

  • A plugin or the theme breaks the answer

    Sometimes

    A plugin or theme that prints anything of its own while WordPress is answering leaves the editor with something other than the JSON it asked for.

    Fix: Switch off the plugin that breaks the answer

How to fix it

Get /wp-json/ answering again

  • Easy
  • Low risk
  • About 5 minutes
  • Steps tested on WordPress 7.1.3

These steps are for Apache, which reads .htaccess.

  1. Step 1: Open Settings, then Permalinks

    Change nothing on the screen.

  2. Step 2: Press Save Changes

    WordPress writes its rules into .htaccess again. "Permalink structure updated." means it could. If it tells you to update .htaccess yourself, it could not write to the file.

  3. Step 3: Open /wp-json/ again

    Text that begins with { means the address is back. Return to the editor and save.

With WP-CLI, a hard flush does the same, but only once WP-CLI has been told the server has mod_rewrite. Put this in wp-cli.yml, in the folder you run WP-CLI from:

wp-cli.yml
apache_modules:
  - mod_rewrite

Then run:

bash
wp rewrite flush --hard

Without that file, the command rebuilds WordPress's list of addresses and leaves .htaccess alone. A hard flush works on a single site only, not on a multisite network.

If WordPress cannot write the file, or the 404 stays, 404 errors on posts and pages that exist has the rules to paste in by hand and what to ask of a server that ignores them. It is the same fault: posts answer 404 there for the reason /wp-json/ does here.

Stop PHP printing messages into the answer

  • Takes care
  • Back up first
  • About 10 minutes
  • Steps tested on WordPress 7.1.3

WordPress never displays PHP errors on REST API requests, whatever WP_DEBUG_DISPLAY is set to. A message that reaches the editor anyway was printed before WordPress had loaded, from wp-config.php on a server whose PHP is set to display errors, or by code that turns display back on.

  1. Step 1: Read the message

    It is the text ahead of the first { in the Response tab. It says what PHP objected to, and names a file and a line. Write both down.

    If the file is inside wp-content/plugins/ or wp-content/themes/, use the fifth fix. If it is wp-config.php, carry on.

  2. Step 2: Turn display off at the top of wp-config.php

    Put this on a line of its own, directly under the opening <?php:

    It has to come first. A message caused by a line above it has already been printed.

    wp-config.php
    ini_set( 'display_errors', 0 );
  3. Step 3: Save the file and save the post again

    If the post saves, the message was the cause.

  4. Step 4: Correct the line the message named

    Turning display off hides the message. It does not put right what PHP objected to. Open the file at that line and correct it, or ask whoever added the line.

PHP's own manual says error display is for development and should never be on for a site on the internet, and advises logging in its place. Ask your host where the PHP error log is. If your hosting panel has a PHP settings page, switch display_errors off there as well: that covers every file.

To undo it: Remove the line from wp-config.php.

Make the site's address match the one you work at

  • Takes care
  • Back up first
  • About 15 minutes
  1. Step 1: Compare the addresses

    Look at the address bar while you edit. Then go to Settings, then General, and read "WordPress Address (URL)" and "Site Address (URL)". Compare the start of each: http or https, and whether www comes before the domain.

  2. Step 2: Look at where the failed request went

    The editor builds the address of each request from the Site Address. In the Network panel, if the failed request's address starts differently from the one in your address bar, the settings are the cause. A browser blocks an http request made from an https page outright.

  3. Step 3: Correct the two settings

    How to change your WordPress URL without locking yourself out covers changing the two addresses, and how to get back in if a wrong one shuts you out.

If both settings already say https and requests still go to http, a proxy or CDN in front of the site is hiding https from WordPress. Mixed content warnings has the lines for wp-config.php that correct it.

Find what refused the request and have the rule changed

  • Takes care
  • No risk
  • About 20 minutes
  1. Step 1: Confirm the refusal

    In the Network panel, a refused request has status 403, which means the server understood it and would not process it. Its Response tab holds a block page in place of JSON. Read it: a block page that names a product tells you whose rule it is.

  2. Step 2: Try a post with one plain sentence

    Add a new post, type one sentence and save it as a draft. If that saves, something in the first post's content matches a firewall rule. HTML, and text that reads like code or a database query, are what such rules match by mistake.

  3. Step 3: Look in the security plugin's log

    If a security plugin with a firewall is active, open its log of blocked requests and find the one made when you saved. Allowing it is done in that plugin's own settings.

  4. Step 4: Ask the host

    If no plugin blocked it, look to a firewall on the server or one in front of the site. Send the host the time, the address of the failed request and your IP address. Ask which rule refused it, and whether it can be relaxed for your site.

Do not leave a firewall switched off to get a post saved. 403 Forbidden covers a security plugin that has blocked your own address, and what to send the host.

Switch off the plugin that breaks the answer

  • Takes care
  • Low risk
  • About 15 minutes
  • Steps tested on WordPress 7.1.3
  1. Step 1: Start with the plugin the response named

    A PHP message with a path through wp-content/plugins/ names the plugin's folder straight after it.

  2. Step 2: Switch it off

    On the Plugins screen, deactivate it.

  3. Step 3: Save the post again

    If it saves, that plugin was the cause. Update it, or report the message to its author.

With WP-CLI, use the plugin's folder name:

bash
wp plugin deactivate plugin-folder-name

If the response names no plugin, the cause has to be found by removal. How to find and fix a WordPress plugin conflict covers switching every plugin off and bringing them back in halves, a mode that does this for your login only, and checking the theme.

To undo it: Activate the plugin again.

When to get help

If /wp-json/ answers with JSON in a browser tab, the failed request carries no PHP message, and saving still fails with every plugin switched off, whatever is refusing the save sits between your browser and WordPress. Finding it means reading the server's and the firewall's logs, which on most hosting only the host can open.

Common questions

Site Health says the REST API is available. Why does saving still fail?

Site Health's test is a request from the server to itself. Yours travels from your browser, through any firewall or proxy in front of the site, and carries the content of your post. It can be refused where the server's own request is not. Go by the Network panel.

Why does it fail on one post and not on others?

Something in that post's content matches a firewall rule: HTML or code, for example. Use the fourth fix. A new post with one plain sentence that saves confirms it.

Does turning WP_DEBUG_DISPLAY on cause this?

Not by itself. WordPress switches error display off for requests that ask for JSON, as the editor's do. A page opened in a browser tab asks for HTML, so with debugging on, /wp-json/ opened in a tab can show messages the editor never receives. Trust the Response tab of the failed request.

More on this subject

Would you rather we fixed it?

Quick Fix is $49. One issue, one site, up to about an hour. No fix, no fee. 30-day warranty. It starts with a free diagnosis.