Build your WordPress website with Elementor.Discover Elementor Affiliate link
Français

Site appearance

Editor and content · Beginner to intermediate

Invalid JSON response in WordPress: three approaches to fix the editor

Fix WordPress’s invalid JSON response using native checks, a private PHP log, and targeted diagnosis of the failing request.

Source published: · Source updated: · Editorial policy

Read the French edition

Start by preserving text that has not been saved

You click Save, Update, or Publish, and WordPress reports that the response is not a valid JSON response. The text sometimes remains visible in the editor, but that does not mean it was saved on the server. Before reloading the page, closing the tab, or signing out, keep a copy of your work.

In the editor menu, use the option to copy all blocks when available. Paste the result into a local document you can find again. If that function does not respond, copy at least the text, title, and recently changed elements. Separately record important settings: featured image, categories, excerpt, status, and intended address.

For complex content, also keep screenshots of the layout. They do not replace the blocks, but help reconstruct an arrangement. Check that your copy actually contains the last paragraph you wrote: an empty clipboard or an older excerpt is not a backup.

WordPress revisions may let you recover versions that were already saved. They do not guarantee recovery of changes that never reached the server. Keep the original tab open during initial checks and avoid testing directly on a published post. A diagnostic draft lets you work without changing what readers see.

Understand the message to choose the right approach

The editor exchanges data with WordPress through its REST API. To save a post, it sends a request and expects a structured response in JSON format. If an HTML page, PHP warning, or incomplete result arrives instead, the editor may display this error. The message therefore describes a failed exchange; it does not identify a single cause.

This is not a request to convert your database to JSON. Nor is there a universal JSON file to delete. Reinstalling WordPress or deleting tables before observing the response risks adding a failure to a problem that may be limited to an expired session.

The three approaches below correspond to different clues. Start with checks within your level of access. If a step requires access you do not have, pass your observations to the person administering the hosting rather than giving them a list of random fixes to apply.

On self-hosted WordPress, file procedures require authorized access to the installation. On WordPress.com, start with the browser, a draft, and Site Health; if your plan does not provide access to configuration files or logs, use the available tools and support. In multisite, addresses and components may depend on network administration: do not apply a change across every site for a single draft.

  • Approach 1: the failure follows a long session, an address change, an HTTPS migration, or a routing error. Check login, URLs, and permalinks.
  • Approach 2: the response contains a block page, unexpected redirect, or server error. Examine hosting, caching, and intermediary protections.
  • Approach 3: the problem appears with a specific block, after a code change, or after activating a component. Isolate the conflict on a copy of the site.

Narrow down the problem with a very simple draft

In another tab, open the post list and create a draft containing only a title and an ordinary sentence. Save it as a draft without publishing. Record whether the problem occurs immediately, only after adding an image, or only with the original content.

If the simple draft works, your account can at least save that content type under those conditions. This points toward a particular element, request size, or different operation. Do not conclude that the server works perfectly: a rule may accept one sentence and reject other content.

If all drafts fail, check whether another authorized user encounters the same problem with their own account. Do not share credentials to perform this test. The difference may involve permissions, session, or browser, but also the selected content type. Compare similar actions.

Also open Tools → Site Health. Record REST API warnings and useful information about WordPress, PHP, and active components. A favorable result on this screen does not necessarily reproduce the save operation failing in your browser. It is an additional clue, not a certificate that every feature works.

Inspect the received response without modifying requests

Use the Network panel with your authorized account. It lets you observe the actual request without server access or code to run. Use the control draft to limit the data exposed in this record.

  1. In Chrome, open developer tools with F12 or the browser menu, then the Network tab. Select the Fetch/XHR filter if necessary. Leave the panel open and reproduce saving the draft once. Locate the corresponding request, often to an address containing wp-json or rest_route.
  2. Open that row and inspect its URL, method, status, and then the Response tab. Saving a post may target a post or page route, while uploading an image uses another route. Choose the request associated with the action rather than simply the first red row. Record its time for comparison with hosting logs.
  3. HTTP status 200 is not enough: the received content may be an HTML page while the editor expects JSON. Conversely, a correctly structured error message may explain a specific refusal. If you see a login page, security page, or the beginning of a PHP warning, retain that information.
  4. You do not need to modify or manually replay the request. Do not publish a complete traffic export: it may contain cookies, tokens, and the draft’s private text. To request help, share only the necessary details after removing those values.

Find the first hop before the HTML page

After saving your text separately, open a control draft. In browser developer tools, open Network, enable Preserve log, then save once. Locate the write request corresponding to the click. It may target a post, page, or autosave. Check the method and address before reading the response. A public request to /wp-json/ can succeed while this write request fails.

For the initial request, record the status and the Content-Type and Location response headers, if the latter exists. Also open the final response body. A hop to a login page can produce a 302 followed by 200 text/html. The login page then works for the browser, but does not contain the JSON the editor expects. Some intermediaries return HTML directly with status 200. If a redirect leaves the domain or switches to HTTP, record the first scheme or host change before modifying the site’s addresses.

A 403 application/json accompanied by code rest_cookie_invalid_nonce indicates that WordPress processed the request and rejected the token. Follow this guide’s reconnection procedure. A 403 text/html with an authentication or block screen points first to the layer that generated that page. Code 403 alone cannot distinguish between them.

Read the route in a local example

The example below illustrates a save request intercepted before its destination: a 302 leads to a login page that responds with 200 in HTML. It is not a successful save response. In your diagnosis, record the initial and final responses separately, then reopen the draft from the post list to determine whether the change was actually retained. An intermediary may also return an HTML page directly with status 200 and no visible redirect.

A 307 redirect preserves the request method; a client may, however, follow a 302 received after a POST with a GET. A 303 normally leads to reading the indicated resource. These differences explain why the redirect status alone does not demonstrate a failed or successful save. Check the next method and reread the saved data. The example is instructional and does not validate your proxy or access rules.

POST /redirection/wp-json/wp/v2/posts/40
HTTP/1.0 302 Found
Location: /connexion-recette
Content-Type: text/plain; charset=utf-8

GET /connexion-recette
HTTP/1.0 200 OK
Content-Type: text/html; charset=utf-8
<title>Connexion recette</title>

Correct the layer intercepting the request

If signing in again on the usual domain changes nothing, record the method, request path, first status, first Location, and final response type. Record the time with its time zone and the request ID if the service shows one. Headers may give a clue about the proxy, but an HTML page may also come from WordPress or a plugin. Ask the administrator with log access whether the origin received the request and which component returned the first hop. Share a redacted record. Mask cookies, tokens, draft content, and sensitive address parameters.

On a copy, the administrator can correct the redirect or access-control rule for the relevant route while retaining the previous setting. Confirm the method and destination before touching permalinks. The repaired path must pass the authenticated write request to WordPress. Keep site access controls in place and also check that an unauthenticated request is still denied. The error response must reflect the authentication and permissions of the actual route. A session cookie without a valid REST nonce is not enough to authorize writing; do not remove that check to obtain a success response.

After the correction on the copy, reload the editor from the usual domain, modify the control draft, and save it. Check the JSON response, then reopen the draft to verify that the text was written. A JSON error response may confirm that the request reaches WordPress, but the expected outcome remains a saved change that can actually be reread. If the modified rule disrupts another access path or leaves the problem unchanged, restore that rule alone and keep the record before resuming diagnosis.

Approach 1: restore a usable login session

This first correction requires your usual credentials and an external copy of your work. The expected result is a successful draft save after signing in again, not merely an administration area that opens. Restore temporary browser exceptions afterward.

  1. After preserving your text, open the usual WordPress login in a new tab. Check the displayed domain and account. If the session expired, sign in normally. Then return to the editor and reload it only when you are sure you can recover the unsaved changes.
  2. WordPress uses the session and a protection token called a nonce for editor requests. A missing or invalid token can make an operation fail even while an older administration page remains displayed. Signing in again and cleanly reloading the editor gives you a current session; it does not correct a missing permission.
  3. If the failure remains limited to your browser, try a separate profile or a private window in which you sign in to the site. This helps compare browser state. It does not, by itself, prove which setting is responsible. If you subsequently clear site data, expect to be signed out and preserve local work first.
  4. A browser extension can also affect a page. Test its effect in a targeted way if observations point to it, then restore your usual settings. Do not turn a diagnostic exception into permanently abandoning browser protections.

Check addresses, especially after an HTTPS migration

Under Settings → General, compare the WordPress address and site address with the intended installation. Look for an old address, staging domain, or inconsistent protocol. Also compare the failing request’s address: administration opened on one domain may send its request elsewhere because of incomplete configuration.

Do not automatically make both fields identical. WordPress can be installed in a subdirectory while displaying the site at the root. This arrangement is valid when correctly configured. Configuration constants and multisite can also change how addresses are managed.

An address correction requires settings permissions, recorded original values, and a rollback method accessible even if login fails. On a copy, confirm with the host how to restore only those values; a full restore of the active database could overwrite new content. If the expected address is not established, stop at recording the observations.

The HTTPS certificate, redirects, and server configuration must be consistent with the chosen address. Do not disable certificate verification to remove the error. After a correction, sign in again at the final address and repeat the same draft test.

  1. Under Settings > General, record WordPress Address (URL) and Site Address (URL). The first corresponds to the installation; the second to public access. Retain the subdirectory when it is part of that arrangement.
  2. If a value is confirmed wrong, correct only that field and click Save Changes. A grayed-out field may be enforced by WP_SITEURL or WP_HOME in configuration; do not try to force it in the browser.
  3. Sign in at the final address and test the same draft. If access works but the problem is unchanged, restore only the modified value when the change was diagnostic. If administration is inaccessible, use the rollback method prepared with hosting.

Regenerate permalinks only when routes are involved

This procedure requires access to permalink settings and is suitable only if the response shows a routing problem. Verify the expected outcome through an authenticated save of the same draft; a public request to the REST root is not enough.

  1. A 404 response on the REST route may indicate that the server is not passing that address to WordPress. The common path is /wp-json/, but an installation without rewritten permalinks may use ?rest_route=/. Use the address the site actually employs rather than diagnosing a failure from a guessed path.
  2. When evidence points to rewriting, retain the current structure and, if Apache uses a local .htaccess file, a private copy of that file with the access needed to restore it. Open Settings > Permalinks once: visiting this screen already triggers regeneration. Change neither the structure nor category bases. Repeatedly clicking Save Changes without new evidence adds no diagnostic value.
  3. If WordPress requests an intervention on server configuration, do not replace the entire file with a generic example. Hosting may contain additional necessary rules. On Nginx, editing .htaccess does not correct server rules; have the provider check the appropriate configuration.
  4. Opening the REST root in the browser checks only a read of that address. It does not validate an authenticated post write. After correction, return to the draft and try the action that failed. That result shows the effect of the change. If a regression comes from a file modified during this intervention, compare it with its original copy and restore only the relevant configuration; do not restore the entire database to undo a rewrite test.

Approach 2: identify server-side or firewall blocking

This approach requires access to the relevant protection logs, or a record sent to the person responsible if you lack permission. The expected result is a specific rule linked to the request and a limited correction that can be reversed to its original value.

  1. If the response shows a protection page, record its request ID, time, and affected path. Check security events in hosting or the service in front of the site. The goal is to find the rule that handled this request, not to disable every protection to see whether the editor starts working. In an existing Cloudflare setup, Security Events lets you narrow the period and filter the request; record the rule ID and applied action. If no matching event is found, do not attribute the refusal to that service by default.
  2. A firewall may consider a code snippet, a particular string, or a volume of data suspicious. On a test draft, compare simple content with the content causing failure. If a reproducible difference appears, give support a reduced example. Do not send an entire confidential article when a few characters suffice for diagnosis.
  3. Request a correction limited to the identified rule or legitimate situation. An overly broad exception across all REST routes could affect other functions. Protections, WordPress permissions, and data validation must remain active. A useful change must be verifiable and reversible.
  4. A 401 or 403 response can also come from WordPress and account permissions without an external firewall being involved. Read the response content before requesting an exception. Giving every author the administrator role is not an editor repair.

Distinguish caching, excessive size, and a service incident

An overly broad cache rule may serve a response that does not match the user or action. Have handling of administration, signed-in users, and write operations checked. Purging a cache can help confirm a clue, but an unsuitable rule will recreate the problem as soon as another response is cached.

If you receive status 413, the request exceeds a limit accepted by a component along the route. Compare a small draft with the affected content, or a small image with the one that fails. A limit may be in the web server, PHP, a proxy, or the protection service; changing a WordPress value does not necessarily change that limit.

For a 500, 502, or 503 error, give support the exact time and route. A service failure, PHP error, or unavailable resource may return an error page instead of the expected result. The status guides investigation but is not enough to attribute the failure to a plugin.

After a limit correction, use a realistically sized file and content. After a temporary incident, check that several saves spaced apart work. Retain your local copy until the draft’s persistence has been confirmed.

Approach 3: isolate a block, theme, or plugin conflict

The expected outcome is to reproduce the difference with a single component change. This approach requires plugin or theme permissions on the copy. Reactivate each component or the original theme before another comparison; content changes remain separate from that rollback.

  1. Prefer a recent staging copy for tests that change site components. Check that it has its own database and cannot trigger production emails or payments. Back up files and the database before any significant deactivation. The goal is to be able to return exactly to the initial state.
  2. If only a complex post fails, copy its content into a test draft. Remove a group of blocks, then save again. Proceed in stages to reduce the example triggering the problem. Keep the original content elsewhere: deleting a block from the only available copy would lose information needed for the repair.
  3. On the copy, start with the recently changed component or the one related to the suspect block. Deactivate it normally through administration, test, then reactivate it before examining another. A return to normal establishes a useful relationship, but the conflict may involve two components. Record their versions and the exact reproduction conditions.
  4. A test with a compatible standard theme can supplement the investigation on the copy. A different result does not necessarily mean that the entire theme is unusable: a custom function or integration may be responsible. Do not abruptly change a public store’s theme just to obtain this diagnosis.

Optional tool: Query Monitor for the failing request

If administration works and you can inspect the affected response, Query Monitor can supplement diagnosis. John Blackbourn’s free plugin is available in the official directory. As of November 2, 2026, the declared version is 4.1.1, requiring at least WordPress 6.3 and PHP 7.4 and declared tested up to WordPress 7.1.4. Recheck these requirements before installing, preferably on a copy.

Information is restricted by default to administrators on a single site and super administrators on multisite. For an authorized authenticated REST request, Query Monitor adds diagnostic headers to the response. The home-page panel or initial editor-load panel does not automatically describe the following REST save.

The expected result is a record tied to the precise request: time, memory, and available PHP errors. If protection blocks it before WordPress or the process stops too early, these details may be absent; absence does not prove the request is healthy. After collecting them, deactivate the temporary tool. There is no need to widen access to visitors. These measurements are produced with a diagnostic tool active; they are not a benchmark of the site without instrumentation.

  1. If no existing tool provides these details, open Plugins → Add Plugin, search for Query Monitor, and verify John Blackbourn and the query-monitor slug, then install and activate it in the intended environment.
  2. While signed in with the authorized account, open the control draft and the browser Network panel.
  3. Reproduce one save; select its authenticated REST request and response headers.
  4. Record x-qm-php-errors-count, any x-qm-php-errors-error-{n} headers, and present x-qm-overview-... fields. They concern this response.
  5. Match an error to the indicated file and component; verify the correction on a copy with the same draft.
  6. Deactivate Query Monitor after diagnosis and keep only useful details in a private space. Do not replay the write just to obtain more information.

Correct unwanted output without hiding a persistent error

If the response contains a PHP warning before the data, first consult the private log already supplied by hosting. Otherwise, this temporary diagnostic is for the person authorized to modify the copy’s files. It requires an existing private directory outside the web root, with a confirmed absolute path writable by PHP.

Open that copy’s wp-config.php and locate existing definitions of WP_DEBUG, WP_DEBUG_LOG, and WP_DEBUG_DISPLAY. Edit them without duplicates. Put the settings before WordPress loads, above the That's all, stop editing! comment where present and before wp-settings.php.

Replace the example path with the log file in the confirmed private directory. Do not keep the fictional value or create a public log to save time. true and false are Boolean values without quotation marks. If the file stays empty, check the path, targeted permissions, and correct installation; this does not demonstrate that no error occurred.

The desired result is a line associated with the attempt when a PHP error is actually produced. WordPress normally suppresses error display in REST responses; unwanted output remains possible before that handling or through a component writing directly to the response. Hiding text does not fix its cause or prove a save occurred. If no line appears after checking the path, return to the network response and relevant service logs; do not blindly broaden permissions. After collection, restore the initial settings and keep the log private.

  1. Preserve a private copy of the initial configuration without placing it in the public directory.
  2. Confirm the log path, then adapt the single definitions of the constants to the example below.
  3. Save, record the time, and reproduce one draft save.
  4. Open the selected private file through SFTP or the file manager; look for the new line at that time.
  5. Identify the affected component from the path, verify its correction on a copy, then save and reopen the draft again.
  6. Restore the initial configuration. If a syntax error blocks the copy, restore only this file through your file access.
define( 'WP_DEBUG', true );
define( 'WP_DEBUG_LOG', '/CHEMIN_PRIVE_CONFIRME/wp-json-debug.log' );
define( 'WP_DEBUG_DISPLAY', false );
@ini_set( 'display_errors', 0 );

Recognize unwanted output in a fictional example

The example below is entirely fictional: the path and component name are invented to illustrate how to read the response. The Warning line precedes a JSON object, so the entire received response is no longer just the structured document the editor expects.

In a real case, the new private-log line provides the time, file, and line to compare with the test. A path under wp-content/plugins/ helps identify the component producing the message, but a shared library or call from elsewhere may require further checking. Do not modify a core file merely to silence the text.

The useful check comes after fixing the cause on a copy: the expected response, no new relevant error, and text found again after reopening. An object containing an identifier in this example is not proof that a real post was saved.

  1. Compare the beginning of the response with the new private-log line from the same attempt.
  2. Identify the component and its version from the actual path.
  3. On a copy, apply the identified correction or its validated corrective update, then return to the same small draft.
  4. Keep the original and restore temporary diagnostic settings before final validation.
Warning: Undefined array key "demo" in /chemin-fictif/wp-content/plugins/exemple-technique/fichier.php on line 42
{"id":123,"status":"draft"}

Confirm that the content is actually retained

Save the test draft, then reopen it from the post list in a new tab. Check the last sentence and modified settings. Then add an element representative of your usual work, such as an image or the problematic block, and repeat the check.

Finally, recover the original content from your preserved copy. Check its status before confirming: a save test must not unexpectedly publish a draft. If the post is already public, review the preview and update it when the changes are ready to be seen.

Record the identified cause, corrected setting, and successful tests. Restore components used during diagnosis and remove temporary exceptions that are no longer needed. If the failure returns, this record will help compare the situations. Troubleshooting is complete when the expected content is saved, retrievable, and usable with the site’s normal permissions and protections.

Sources and references

Use these references to check the features, requirements and limitations described. Reading documentation is not a practical test.

View 20 references

English translation of the reviewed French edition. Code examples retain their original identifiers, comments and output strings for reproducibility. Linked exercise files and original screenshots may contain French. No new practical tests or price checks are implied by translation.

Continue reading in English