Fixing the Publishing Failed Error
The editor asked the REST API to save the post and got a refusal, a redirect or a non-JSON page back. The second sentence of the message tells you which, and the browser's network panel shows the actual response in under a minute.
The block editor saved through the REST API and the API did not answer with a success. "Publishing failed." is the editor's summary; the second sentence is the diagnosis, and there are three of them. Read it, then open the browser's network panel, where the actual response to the save request is sitting with a status code and a body that names the problem.
The three variants
| Message | What the editor received | Usual cause |
|---|---|---|
| "The response is not a valid JSON response." | A 200 with HTML, or a redirect | Permalinks, mixed URL, a plugin printing output |
| "You are probably offline." | No response — network error | Firewall, blocked REST, SSL, timeout |
| "Sorry, you are not allowed to edit this post." or a 403 | A JSON error with a code | Security plugin, nonce expiry, capabilities |
The first is common enough to have its own guide. The third names a permission check that failed, which is either a real capability gap or a security layer that blocked the request. The second is the one that sends people to check their Wi-Fi.
Look at the actual request
Open the browser's developer tools, switch to the Network panel, and click Publish again. Find the request to /wp-json/wp/v2/posts/<id> (or /index.php?rest_route= on sites with plain permalinks). Its status and response body are the facts:
- 200 with HTML — the API route returned a page. Permalinks are broken or a plugin printed something before the JSON.
- 301 or 302 — the request was redirected, usually from
httptohttpsor betweenwwwand the apex. The site URL and the address bar disagree. - 401 or 403 with JSON — WordPress refused:
rest_cookie_invalid_nonceusually means a cache or proxy served a stale nonce, since the editor refreshes an expired one on its own;rest_forbiddenmeans capabilities, a security plugin, or a cookie that never arrived because the request went cross-origin. - 403 with HTML — a web application firewall or
mod_securityblocked the request body before WordPress saw it. - 500 — PHP failed on the save; the error log has the trace.
- No status, "failed" — the browser could not complete the request: a certificate the browser rejects, a blocked port, a timeout.
Permalinks and the REST route
The API lives at /wp-json/, which is a rewrite rule. If the rewrite rules are stale — after a migration, a server change, or a .htaccess that was replaced — the route 404s or returns the home page. Settings › Permalinks › Save Changes rewrites the rules and is the first thing to try. Sites on nginx need the try_files rule pointing at index.php; sites on Apache need mod_rewrite and a writable .htaccess, both covered in permalinks not working.
URL mismatch
The editor sends requests to the API URL WordPress printed into the page, which is built from site_url(). If the site is open at https://www.example.com and siteurl says http://example.com, the request goes cross-origin or through a redirect, and the browser either blocks it or the editor receives the redirect instead of JSON. Make the stored URLs match the served address, including scheme — WP_HOME and WP_SITEURL force it when the admin is hard to reach.
Security plugins and firewalls
Plugins that disable the REST API for logged-out users are fine; those that disable it entirely, or restrict it to specific routes, break the editor for everyone. Check the plugin's REST settings before disabling it. A firewall rule triggered by the post content — a block containing something that looks like SQL or a script, an embedded form — returns a 403 before PHP runs, and shows up as a 403 with an HTML body from the firewall rather than from WordPress. Whitelisting the wp-json path for authenticated users is the usual rule.
Certificates and loopback
"You are probably offline" on an HTTPS site often means the browser trusts the certificate for the page but a redirect sent the API request to a host the certificate does not cover, or the certificate expired between loading the editor and saving. Site Health reports both the REST API check and the loopback request, and a failure there usually matches the editor's.
Verify
Fix the cause the network panel pointed to, then publish again without reloading — the content is still in the editor. The request should return 200 with a JSON body containing the post. Then run Tools › Site Health: "The REST API encountered an error" should be gone from the list. If the editor still fails but the API check passes, the failure is specific to this post's content, and the firewall rule is the next thing to read.
Frequently asked
- The editor reports 'You are probably offline' whenever the REST request fails at the network level — a timeout, a blocked request, a certificate problem, or a firewall that dropped the connection. The browser is online; the API endpoint was unreachable.
- Not while the tab is open. The editor keeps the post in memory and in session storage for that tab, and clicking Publish again after fixing the cause usually saves it. Copy the content out of the editor before closing or reloading the tab if the fix involves changing settings.
- Because it submits a normal form to post.php and does not use the REST API. The block editor saves through /wp-json/, and anything that blocks or breaks that path — a disabled REST API, a rewrite problem, a firewall rule — affects only the block editor.