API & webhooks
CORS Policy and Fetch: Diagnose Readable and Opaque Responses
Diagnose a Fetch CORS failure without using no-cors as a JSON workaround, and distinguish a rejected read from an HTTP error or a request that already ran.
Start with the browser request and its observable result
A fetch call can fail before it produces a response that JavaScript may read. A CORS policy error is one possible reason, alongside network and transport failures. Readable HTTP errors behave differently: fetch can resolve with a Response whose status is 401, 404 or 500.
Keep these outcomes distinct in the interface. A rejected promise does not provide a trustworthy HTTP status for the application to invent, and a readable 404 should not be labelled as a network outage. The user needs a useful action based on the observed condition.
Handle a permitted JSON response explicitly
async function fetchVisibleJson(url, fetcher = fetch) {
const response = await fetcher(url, {mode: "cors"});
if (response.type === "opaque") {
throw new Error("The response is not readable by this page.");
}
if (!response.ok) throw new Error(`HTTP ${response.status}`);
return response.json();
}
The helper requests normal cross-origin sharing and checks a readable response before parsing JSON. It does not repair the server's policy. A caller still needs error handling for a rejected request, a non-success HTTP status and malformed JSON.
For a local fixture, return one valid object, a readable 404 and a malformed JSON body. Then remove the sharing permission from the fixture's response. The first three outcomes remain distinguishable from the browser-level rejection, which does not reveal the blocked body to the script.
Understand why no-cors is not a JSON-reading fix
Changing mode to no-cors does not grant permission to read a blocked cross-origin API response. It restricts the request and can produce an opaque response whose status, headers and body are unavailable to ordinary script access.
The Request mode documentation explains that boundary. A promise that resolves with an opaque response is not equivalent to receiving the JSON data the application required. Do not treat its synthetic status zero as an actual HTTP status returned by the server.
Also do not relabel a JSON write as text/plain merely to avoid the preflight that its intended media type requires. The endpoint's body contract and browser permission are separate requirements. A request that bypasses one check by changing its meaning is not a successful reproduction of the original operation.
A blocked read does not always mean nothing happened
Some cross-origin requests can be sent without a preflight, while response access is still controlled by CORS. If such a request reaches a state-changing endpoint, a later read failure does not prove that the operation had no effect.
Before retrying a write after an uncertain outcome, use the endpoint's documented recovery or idempotency mechanism. Repeatedly clicking a button because the browser hid the response can create duplicate work when the service has already accepted the first request.
Check credentials as their own part of the contract
When an API intentionally uses cross-origin cookies, both the request's credential mode and the server's sharing policy matter. Cookie attributes and browser restrictions also apply. Adding credentials: include does not override a missing permission or force a browser to accept every cookie.
The Request credentials reference describes the fetch setting. A service using a Bearer token in an explicit header is a different setup and can require permission for that request header. Follow the documented mechanism rather than combining unrelated examples.
Use the network trace and a controlled fixture
Inspect the requested URL, method and origin, then the preflight if present and the actual response. Compare a browser call with server logs on infrastructure you control. A command-line client reading the same URL can confirm server behavior, but it does not reproduce the browser's sharing restrictions.
The CORS Header Checker helps review one pasted header block and exact method tokens. It cannot grant access, send the missing preflight or determine a complete browser result from that block alone. Verify the complete request path after correcting the relevant server or client setting.


