Misleading CORS Errors

This post is about a problem with CORS (cross-origin resource sharing) in Chrome. CORS is one of the security mechanisms built into browsers to prevent other sites from consuming your content or APIs unless specifically allowed. If you are a native mobile developer or a back-end developer consuming APIs you may never encounter CORS errors, because CORS only applies to the browser. If you need some background on CORS, Mozilla has an excellent write-up. I’m going to discuss an issue I’ve encountered with misleading CORS errors in Chrome and ways to work around the error to discover the actual problem.

At some point Chrome changed the way CORS is reported in the developer tools, perhaps as far back as 2019. The current behavior in Chrome is that CORS errors take precedence over network errors. So today if your front-end application has a problem with the back-end service, it might report the problem as CORS when it is actually something else entirely. I am not the only developer that encountered this problem. If you read the error message (good developers read errors closely, don’t they?), you will end up going down the wrong path to solve the problem. Here’s the error I see in Chrome:

Access to XMLHttpRequest at ‘https://my.long.url.com’ from origin ‘http://localhost:8080’ has been blocked by CORS policy: No ‘Access-Control-Allow-Origin’ header is present on the requested resource.

The Chrome developer tools show only a CORS error in the console

It looks like a CORS error, but the underlying issue ended up being something else entirely. In my case, the problem was that the service layer was down. There is a reverse proxy in front of the service, and the reverse proxy was correctly returning an HTTP 503 response, because the service application behind the proxy had crashed. But that HTTP response lacked the Access-Control-Allow-Origin header. It was missing because the underlying application was setting those headers, not the reverse proxy. Since the application was down, the headers were not set. This causes Chrome to display the CORS error in the developer console instead of the network error.

Finding the Actual Problem

Because I was confident that there was no CORS misconfiguration in the server application, I had to look elsewhere for the answer. My first choice is to try a different browser. Another browser sometimes displays the same errors differently. I tried Safari. Same result. Edge? Same result. FireFox? A-ha! I saw the 503 error in the JavaScript console and also in the network tab in FireFox.

The FireFox developer tools show both the 503 HTTP error code and the CORS error in the console

FireFox also reported the CORS error along with the network error. The JavaScript code still failed and kept the content of the 503 response from reaching the application code, which is the expected behavior for CORS errors. But that information was in the developer console. This is much more helpful to me as a developer. I assume that Chrome and the other browsers view this as a security issue and just deny the request when the header is missing, even in the developer console.

Another approach to finding the real issue would be to use a tool not affected by CORS, such as curl or PostMan. I used curl adding the -v flag and see the 503 response in the headers returned from the call:

The curl command-line tool shows a 503 error response in the HTTP headers

As another alternative, I could even start an instance of Chrome without the CORS protections enabled using the terminal on my Mac :

open -n -a /Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome --args --user-data-dir="/tmp/chrome_dev_test" --disable-web-security

This also worked and I could now see the 503 error in the Chrome developer console. I do not like to develop using Chrome with security disabled because it ultimately hides issues like CORS which can occur as legitimate errors. But it’s a good tool for troubleshooting.

Perhaps we could fix the problem by configuring the reverse proxy to add the missing Access-Control-Allow-Origin in the case of 5xx HTTP responses? Or maybe configure the reverse proxy to add the CORS-related headers all the time instead of the underlying application? I’m not sure, finding information about this situation has been difficult.

The bottom line is this: If you see a CORS error when there were none previously and believe CORS is configured correctly on the back end, use some other tool to ensure you are troubleshooting the correct error.