You click Update in the block editor and get a red banner: “Updating failed. The response is not a valid JSON response.” or “Updating failed. Could not get a valid response from the server.” It is showing up in the WordPress.org support forums again this week, and plenty of the reports come after a host changed something on the server, which a lot of hosts have been doing since the critical PHP security release announced on October 21, 2026.
The editor saves posts through the WordPress REST API (/wp-json/wp/v2/...). The error means the editor expected JSON but got something else: a PHP warning glued to the front of the response, an HTML error page, a 403 from a firewall, a 404 from broken rewrite rules or a redirect. The fix depends on which of these you have, so I check the response first and only then change things.
Back up your files and database before you change anything below.
Step 1: See what the server actually returned
Open the editor, press F12, go to the Network tab, click Update again and select the failed request (usually posts/123?_locale=user or similar). Look at the status code and the Response tab. That one request tells you which section below to use.
You can also test the REST API from the shell:
# Should return JSON that starts with {"name":...
curl -sI https://example.com/wp-json/ | head -n 5
curl -s https://example.com/wp-json/ | head -c 300
# The same route without pretty permalinks
curl -s "https://example.com/?rest_route=/" | head -c 300
If ?rest_route=/ returns JSON but /wp-json/ returns a 404, your rewrite rules are broken (step 3). If both return JSON but the editor still fails, look at the editor request itself: a PHP notice in front of the JSON, a 403 or a 413 (steps 2 and 4).
Step 2: PHP warnings printed into the response
This is the most common cause after a PHP upgrade. An older plugin or theme throws a deprecation notice or warning on the new PHP version, display_errors is on, and the notice text lands in front of the JSON. The response tab shows something like <br /><b>Deprecated</b>: ... followed by {"id":123,....
Stop printing errors and log them instead. In wp-config.php, above the /* That's all, stop editing! */ line:
define( 'WP_DEBUG', true );
define( 'WP_DEBUG_LOG', true ); // writes to wp-content/debug.log
define( 'WP_DEBUG_DISPLAY', false ); // never print errors into responses
@ini_set( 'display_errors', 0 );
That setup is the one recommended in the official debugging docs. Save the post again, then read the log to find the plugin behind it:
tail -n 50 wp-content/debug.log
grep -oE "wp-content/(plugins|themes)/[^/]+" wp-content/debug.log | sort | uniq -c | sort -rn
Update or replace whatever the log points at. When you are done, set WP_DEBUG back to false and delete debug.log, because it is publicly readable on many servers. If the server’s php.ini has display_errors = On, turn it off there too. That is a development setting.
Also check for stray output. A blank line or a UTF-8 BOM before <?php in wp-config.php or a theme’s functions.php breaks the JSON just as badly. This lists PHP files that start with a BOM:
grep -rlI $'^xEFxBBxBF' wp-config.php wp-content/themes wp-content/plugins --include=*.php
Step 3: 404 on /wp-json/ (rewrite rules)
If /wp-json/ gives a 404 but ?rest_route=/ works, the pretty-permalink rules are missing. This often happens after a migration, a server move or a restore that skipped .htaccess. Flush them with WP-CLI:
wp rewrite flush --hard
The --hard flag also rewrites .htaccess (single-site only). If .htaccess is not writable, put the default WordPress block back by hand:
# BEGIN WordPress
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
RewriteBase /
RewriteRule ^index.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>
# END WordPress
On nginx there is no .htaccess, so the site block needs the usual front-controller rule:
location / {
try_files $uri $uri/ /index.php?$args;
}
Step 4: 403, 413 or an HTML block page (firewall and limits)
If the response is an HTML page saying “Forbidden” or “Not Acceptable”, or it carries your WAF or CDN branding, a firewall rule matched the post body. That happens a lot with posts that contain code, <script> embeds or SQL-looking text, and hosts that just added emergency WAF rules make it more likely. Check the ModSecurity or WAF log for the rule ID and whitelist that rule for /wp-json/wp/v2/. Don’t switch the whole firewall off.
A 413 Request Entity Too Large on long posts means the request body limit is too small. On nginx, raise it in the server block and reload:
client_max_body_size 64m;
Then make sure PHP’s post_max_size is at least as large.
Step 5: Redirects and URL mismatch
If the request shows a 301/302, WordPress is redirecting the REST call. Usually home and siteurl disagree (http vs https, www vs non-www). Check them:
wp option get home
wp option get siteurl
# Fix both to the same canonical URL
wp option update home 'https://example.com'
wp option update siteurl 'https://example.com'
The same mismatch also causes login loops, which I covered in fixing the WordPress admin login redirect issue. Behind Cloudflare or a reverse proxy that terminates SSL, also make sure WordPress knows the request was HTTPS, or it keeps redirecting to itself.
Step 6: Plugin conflict or corrupted core
If the request returns a clean 200 but the editor still fails, a security plugin may be disabling the REST API for logged-in users, or another plugin may be changing the response. Test quickly without touching the dashboard:
wp plugin list --status=active --field=name > /tmp/active-plugins.txt
wp plugin deactivate --all
# test saving a post, then re-enable one by one:
wp plugin activate $(cat /tmp/active-plugins.txt)
If nothing helps, verify core files with wp core verify-checksums and replace anything that does not match, as described in reinstall WordPress core using WP-CLI.
Why this works
The block editor runs in JavaScript and parses every save response with a JSON parser. One extra byte before the opening { (a PHP notice, a BOM, an HTML error page) makes the parse fail, and the editor shows the same generic message whatever the real cause was. Reading the raw response turns that vague error into one specific problem: output, routing, firewall, redirect or plugin.
Doing it in OpenPanel vs cPanel
If the error started right after a PHP version change, test the site on a different version first. In OpenPanel you go to PHP → Select PHP version, click the version next to the domain and hit Change. The server admin can do the same from the shell with opencli php-domain example.com --update 8.3. In cPanel the equivalent is the MultiPHP Manager. Either way, use a temporary version switch to confirm which plugin breaks on the newer PHP. As of 2026-10-28, don’t stay on an unsupported PHP branch. See my notes on the PHP RCE patch for WordPress.
Prevention
- Keep
display_errorsoff andWP_DEBUG_DISPLAYfalse on production. Log errors instead. - Before a PHP upgrade, test on staging and read the log for deprecations.
- Include
.htaccess(or your nginx config) in backups and migrations. - When you add WAF rules, test a post save in the editor right away.
- Make sure
homeandsiteurlmatch exactly.
TL;DR
“Updating failed. The response is not a valid JSON response” means the editor’s REST API call came back as something other than clean JSON. Open DevTools → Network and read the failed response. PHP notices: set WP_DEBUG_DISPLAY to false and fix the plugin in debug.log. 404: run wp rewrite flush --hard. 403/413: whitelist the WAF rule or raise the body size. Redirect: make home and siteurl match. Back up first.

