How to fix "The REST API encountered an error" in WordPress Site Health
Site Health tests the REST API with one request from the server to the site's own address. "The REST API encountered an error" means no answer came back at all. The line that begins "REST API Response:" says why, and each reason has its own fix.
- By
- WP Ministry
- Published
- Tested on
- WordPress 7.1.3, PHP 8.3.35
In short
- The test is a request the server makes to its own address. A site that loads in every browser can still fail it.
- "Encountered an error" means no answer arrived. "Encountered an unexpected result" means an answer arrived with a status other than 200.
- The line that begins "REST API Response:" gives the reason: a cURL error number, or an HTTP status.
- cURL error 28 beside "An active PHP session was detected" points at a plugin that leaves a PHP session open.
- (404) Not Found from the web server's own page means the rewrite rules are missing. Save the permalink settings again.
- Closing the REST API to signed-out visitors does not fail this test. The request is signed in as you.
Site Health tests the REST API by sending one request from the server to the site's own address and reading what comes back. "The REST API encountered an error" means nothing came back. The request could not find the site by its name, could not connect, ran out of time, or was sent around in a circle. The result is on the Status tab at Tools, then Site Health, under critical issues, with the badge "Performance".
The server makes this request to itself, so the result says little about what visitors see. A site that loads in every browser can fail it. The block editor asks from your browser, not from the server, so it may still save. Open a post, change a word and save it to find out. If saving fails with "Updating failed." or "Publishing failed.", how to fix "Updating failed" starts from the browser's side of the same fault. If the editor does not draw at all, see "The editor has encountered an unexpected error".
Check which result you have
Site Health has three results for a REST API that does not pass, and they mean different things. All three carry the badge "Performance".
| Result | Listed under | What happened |
|---|---|---|
| "The REST API encountered an error" | Critical issues | No answer arrived. The response line reads "(http_request_failed)" and the reason. |
| "The REST API encountered an unexpected result" | Recommended improvements | An answer arrived, with a status other than 200. The response line gives the status, as in "(404) Not Found". |
| "The REST API did not behave correctly" | Recommended improvements | The answer had status 200 and was not what the test asked for. The result adds "The REST API did not process the context query parameter correctly." |
Click the result to open it. Each begins with the same two sentences: "The REST API is one way that WordPress and other applications communicate with the server. For example, the block editor screen relies on the REST API to display and save your posts and pages." The first two results then end with two lines like these:
REST API Endpoint: https://example.com/wp-json/wp/v2/types/post?context=edit
REST API Response: (http_request_failed) cURL error 28: Operation timed out after 10002 milliseconds with 0 bytes receivedThe first is the address WordPress asked. The second is what it got. The words after a cURL error's number come from the server's copy of curl and differ a little from one server to the next. The number is what matters.
What the test sends
The test runs each time the Site Health screen loads, so reloading the screen runs it again. WordPress asks the address on the "REST API Endpoint:" line for the description of the Posts post type, the way the editor asks for it. It sends your own login cookies and a security token, called a nonce, with the request, waits ten seconds, follows up to five redirects, and by default does not check the site's https certificate. It passes when the answer has status 200 and is JSON that includes a list of capabilities, which only a signed-in user who can edit posts is given.
Two things follow from the request being signed in as you:
- A plugin that closes the REST API to visitors who are not signed in does not fail the test.
- A password prompt in front of the site does not fail it either, as long as PHP is given the name and password your browser sent. WordPress adds them to the request.
With permalinks set to Plain, the endpoint has the form https://example.com/index.php?rest_route=… and needs no rewrite rules.
Read the response line
| "REST API Response:" reads | What it means | Go to |
|---|---|---|
| (http_request_failed) cURL error 6 | The server could not find the site's own name. | The third fix |
| (http_request_failed) cURL error 7 | The server found the name and could not connect. | The third fix |
| (http_request_failed) cURL error 28 | No answer came within ten seconds. | The second fix if Site Health also lists "An active PHP session was detected". Otherwise the third. |
| (http_request_failed) Too many redirects | The address redirects in a circle. | ERR_TOO_MANY_REDIRECTS if browsers loop as well. Otherwise the third fix. |
| (404) Not Found | Nothing answers at the address. | The first fix |
| (403) Forbidden or (401) Unauthorized | Something understood the request and refused it. | The second fix for a plugin, the third for a firewall. The next section tells them apart. |
| (500) Internal Server Error | PHP stopped while it was answering. | The second fix |
No response line, and the sentence about the context query parameter | The answer was not the JSON the test asked for. | The second fix |
Ask the same address from the server
Site Health shows a status and not the answer itself. The answer says who gave it. Over SSH, from the folder WordPress is installed in, print the address the test uses:
wp eval 'echo rest_url( "wp/v2/types/post" ), "\n";'Then ask it, with the address that was printed in place of the example:
curl -sS -i -k --max-time 10 https://example.com/wp-json/wp/v2/types/post | head -n 20-sS hides the progress meter and keeps any error message. -i prints the status line and the headers ahead of the answer. -k skips the certificate check, as the test does, and --max-time 10 gives up after the same ten seconds. This request carries no login, so it asks for the public description of the post type. A healthy site answers with a first line that ends in 200 and, under the headers, one line of JSON that begins {"description".
| What comes back | What it means |
|---|---|
curl: (6), curl: (7) or curl: (28) | The server cannot reach its own address, WordPress or no WordPress. The numbers are the ones Site Health prints. Use the third fix. |
| 404 and a page of HTML | The web server answered, and the request never reached WordPress. Use the first fix. |
404 and JSON with the code rest_no_route | WordPress answered. Code on the site has removed this address from the REST API. Use the second fix. |
401 or 403 and JSON with a code and a message | A plugin or a snippet refused the request. Use the second fix. |
401 and a header that begins WWW-Authenticate: Basic | A password prompt in front of the site. See the questions at the end. |
| 403 and a page of HTML | A firewall refused the request. Use the third fix. |
200, with text ahead of the first { that names a .php file | A PHP message is printed into the answer. Use the second fix. |
200 and a header that begins Set-Cookie: PHPSESSID | Something on the site starts a PHP session. Use the second fix. |
A 401 here while Site Health says "The REST API is available" is not a fault. It means the REST API is closed to visitors who are not signed in, and this command is one.
Without SSH, open the endpoint address in a browser tab, leaving off ?context=edit. That shows what a visitor gets, which is enough to tell the 404, 403 and PHP message cases apart. It cannot show a cURL error, because your browser is not the server.
Where it goes wrong
A page request passes through each of these in turn. This one comes from the web server.
- Browser
- DNS
- HTTPS
- CDN or firewall
- Web server (this error comes from here)
- PHP
- WordPress
- Database and files
What causes it
The server cannot reach its own address
CommonThe test is a request from the server to the site's own address. When the server cannot find that name, cannot connect to it, or gets no answer within ten seconds, the result is this message with a cURL error number. Visitors reach the site by another road, so it loads for them all the same.
A plugin or theme leaves a PHP session open
SometimesPHP lets one request at a time use a session. Code that starts a session and does not close it holds it for as long as the Site Health screen is loading. The test's request carries the same session cookie, so it waits for the session until its ten seconds run out.
The rewrite rules do not reach /wp-json/
CommonWith pretty permalinks the REST API's address 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 and Site Health reports "The REST API encountered an unexpected result".
A plugin, a snippet or a firewall refuses the request
SometimesCode that closes the REST API to everyone, or a firewall that turns the server's own request away, answers (403) Forbidden or (401) Unauthorized. Closing the API only to visitors who are not signed in does not do this, because the test is signed in as you.
Fix: Find the plugin behind the result and switch it off, or Have the host let the server reach its own address
A PHP error breaks the answer
SometimesA PHP message printed in front of the JSON leaves an answer the test cannot read, which it reports as "The REST API did not behave correctly". A PHP error that stops the request is reported as (500) Internal Server Error.
How to fix it
Save the permalink settings again
- Easy
- No risk
- About 5 minutes
- Steps tested on WordPress 7.1.3
For "(404) Not Found" when the 404 is the web server's own page. These steps are for Apache, which reads .htaccess.
Step 1: Open Settings, then Permalinks
Change nothing on the screen.
Step 2: Click Save Changes
WordPress writes its rules into
.htaccessagain and answers "Permalink structure updated." If it answers "You should update your .htaccess file now." instead, it could not write the file, and the rules it wanted to write are shown at the bottom of the screen.Step 3: Reload Site Health
Go back to Tools, then Site Health. The test runs again as the screen loads, and "The REST API is available" is listed under Passed tests.
If the 404 stays, or WordPress could not write the file, 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. The .htaccess generator writes a whole file with WordPress's block in it. To do the same from the command line, see the first fix on the "Updating failed" page.
Find the plugin behind the result and switch it off
- Takes care
- Low risk
- About 15 minutes
- Steps tested on WordPress 7.1.3
How you find the plugin depends on the result.
cURL error 28 and "An active PHP session was detected". Site Health lists the second result as a critical issue of its own, with the text "A PHP session was created by a session_start() function call. This interferes with REST API and loopback requests." Search the site's code for that call:
grep -rl --include="*.php" "session_start" wp-contentEach line is a file that contains it. The folder after wp-content/plugins/ is a plugin's folder name, and a file under wp-content/themes/ belongs to a theme. A file on the list is a suspect, not a culprit: code that closes its session before WordPress sends a request does no harm. Switch the listed plugins off one at a time and reload Site Health after each.
(403) Forbidden or (401) Unauthorized, answered in JSON. The answer to the command in the section above carries a code and a message:
{"code":"rest_api_closed","message":"The REST API is closed on this site.","data":{"status":403}}Search for the code, with yours in place of rest_api_closed:
grep -rl --include="*.php" "rest_api_closed" wp-contentThe file it prints is the one that refuses the request. If nothing is printed, search for rest_authentication_errors, the hook WordPress gives plugins for refusing REST API requests, and for rest_endpoints if the code was rest_no_route.
"The REST API did not behave correctly", or (500) Internal Server Error. For the first, the answer names the file. The text ahead of the first { is a PHP message with a path in it, and the folder after wp-content/plugins/ is the plugin. If the path is wp-config.php, the second fix on the "Updating failed" page is the one to use.
For a 500, the error is in the log and not in the answer. How to turn on WordPress debug mode shows how to switch the log on and read it, and 500 Internal Server Error covers the cases where the log stays empty.
Then switch it off. On the Plugins screen, click Deactivate under the plugin's name. With WP-CLI, use its folder name:
wp plugin deactivate plugin-folder-nameReload Site Health. If the REST API result has moved to Passed tests, that plugin was the cause. Update it, or send its author the result's two lines, and keep it off until it is corrected.
If the file is in the theme, look in its functions.php for a snippet someone added. Remove the snippet, or ask whoever added it. If the searches name nothing, 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.
To undo it: Activate the plugin again.
Have the host let the server reach its own address
- Easy
- No risk
- About 20 minutes
Step 1: Check the address first
The "REST API Endpoint:" line begins with the Site Address from Settings, then General. If that is not where the site really lives, with http where it should be https, an old domain, or a staging name, the server is asking the wrong place. How to change your WordPress URL without locking yourself out covers correcting it.
Step 2: Make the request from the server
Run the two commands in "Ask the same address from the server". If curl fails with the same number, the server cannot reach its own address whatever WordPress does, and no setting in the dashboard will change that.
Step 3: Send the host what you have
Send the two lines from Site Health, the output of the curl command, and the time you ran it. WordPress's own documentation gives the question to put: ask "whether server-side security rules, firewall rules, DNS configuration, SSL configuration, or HTTP authentication are blocking the site from requesting its own URL."
Step 4: If a firewall service sits in front of the site
A request from the server to the site's name can travel out through that service like any visitor's. A (403) Forbidden answered with a block page can be that service refusing the server's address. Letting the server's own IP address through is done in the service's settings, not in WordPress. 403 Forbidden has what to look for in a security plugin's log and what to send a host.
The same closed road stops other things WordPress does by calling itself. It uses such requests to start its scheduled tasks and to check a change made in the plugin and theme file editors, and Site Health reports them in a result of their own, "Your site could not complete a loopback request". A scheduled post that shows "Missed schedule" can be the same fault seen from another side.
When to get help
If the response line is a cURL error, Site Health reports no PHP session, and the same request made over SSH fails with the same number, the fault is in how the server reaches its own address. That is its DNS, its firewall or its network, and only the host, or someone with access to the server, can change those.
Common questions
Is my site broken for visitors?
Not by this result. It reports on one request the server made to itself. Visitors' requests come from outside and are not part of the test. What can be affected is the editor, if the address also fails from your browser, and the work WordPress does by calling itself, such as starting scheduled tasks.
Why does the editor still save when Site Health reports an error?
The editor's requests come from your browser. The test's request comes from the server. When only the server's road to its own address is closed, the editor is not affected. The reverse also happens: the test passes and saving fails, because a firewall refuses what your browser sends. How to fix "Updating failed" covers that side.
My site is behind a password prompt. Is that the cause?
Not by itself. WordPress adds the name and password your browser sent to the test's request whenever PHP reports them, so a prompt in front of the whole site does not fail the test. If the server does not pass them on to PHP, the request arrives with no password and is answered (401) Unauthorized. Whether PHP is given them is part of the server's configuration, so that is a question for the host.
I closed the REST API to the public with a plugin. Is that why?
No, if the plugin lets signed-in users through. The test sends your login cookies, so WordPress treats it as you. A plugin or snippet that refuses everyone, signed in or not, does fail it, with (403) Forbidden or (401) Unauthorized.
Can I run Site Health's test from the command line?
Not usefully. Called from WP-CLI, the test has no login cookies to send, and it reports (401) Unauthorized or (403) Forbidden on a site with nothing wrong. Read the result on the Site Health screen, and use the curl command above to see the answer.

