Skip to content

Flutter web errorFlutter web: “ClientException: XMLHttpRequest error.”

The app works on Android and iOS, but in Chrome every API call fails with ClientException: XMLHttpRequest error. Newer versions of the http package say ClientException: Failed to fetch instead, and Dio says The XMLHttpRequest onError callback was called. In each case the browser blocked the request or it never got an answer, and the browser keeps the reason from the page, so Dart can’t tell you which. The real reason is in the browser’s DevTools console.

Short answer

Open Chrome DevTools (F12), look at the Console and Network tabs, and run the request again: the red message there names the cause. Most often it is CORS: the API doesn’t send an Access-Control-Allow-Origin header for your web app’s address, and the fix is on the server, not in Flutter. Next come an http:// API called from an https:// page (mixed content), a Firebase Storage bucket with no CORS setting, and a server that is down or has a bad certificate. Starting Chrome with --disable-web-security only hides CORS on your own machine; your users still hit it.

What the browser blocked, and the fix

  1. 01

    The API doesn’t allow your web app’s origin (CORS)

    “CORS is a mechanism that browsers use to control how one site accesses the resources of another site.” Flutter, Display images on the web: CORS

    The console says blocked by CORS policy: No 'Access-Control-Allow-Origin' header. Phones don’t apply CORS, which is why only the web build fails. Add your web app’s address to the server’s CORS settings and answer OPTIONS preflight requests. While developing, run flutter run -d chrome --web-port 5000 so the localhost address stays the same and can be allowed too.

  2. 02

    An http:// API called from an https:// page

    “Mixed content requests are insecure requests for resources from a secure context” MDN, Mixed content

    A web app served over https can’t make requests to a plain http:// API (http://localhost is the exception); the browser blocks them as mixed content. The phone build may still work, so the web build looks like the only one broken. Serve the API over https.

  3. 03

    Firebase Storage downloads with no CORS rule

    “To download data directly in the browser, you must configure your Cloud Storage bucket for cross-origin access (CORS).” Firebase, Download files with Cloud Storage on Web

    Reading a file’s bytes from Firebase Storage in the browser needs a CORS rule on the bucket. Write a cors.json that lists your web app’s origins and the GET method, then apply it with gcloud storage buckets update gs://your-bucket --cors-file=cors.json (older guides use gsutil cors set).

    [{"origin": ["https://your-app.web.app"], "method": ["GET"], "maxAgeSeconds": 3600}]
  4. 04

    The server is down, the URL is wrong, or the certificate is bad

    A request that never gets an answer gives the same error. Open the API URL in a browser tab: if it fails there or shows a certificate warning, fix the server or the address first. A server that crashes with a 500 often sends no CORS headers on that error, so it shows up as a CORS problem too: check the server log. A self-signed certificate that a phone build accepts through a custom HttpClient is still rejected by the browser.

Checked against the vendor’s docs on : Flutter: Display images on the web (CORS); MDN: Mixed content; Firebase: Download files with Cloud Storage on Web (CORS configuration).

Rather hand it over?

Fixed scope, fixed price, paid upfront. The work happens in writing; no call needed.

Related: “Blocked by CORS policy” · Firebase Functions CORS error · Flutter “Unable to load asset” · Flutter “type 'Null' is not a subtype of type 'String'”

Questions

More on this error

Can I fix CORS in the Flutter code?

No. CORS depends on the headers the server sends back, and the browser enforces it. Adding Access-Control-Allow-Origin to the request in Flutter does nothing. Change the server, or call the API through your own backend.

Why does it work in Postman and on my phone?

Neither is a browser, so neither applies CORS or mixed-content rules. Only the web build runs inside the browser’s checks.

Can you fix it for me?

If one bug is the whole problem, the App Fix Ticket covers it: a written diagnosis first, then the fix. If the app has more going on, the Launch Check is a written check of the whole app. Each issue found is rated critical, high, medium or low, with where it is and how it was confirmed. No issues worth fixing, no charge. If the Launch Check finds nothing rated medium or higher, Simon refunds the full $450. You keep the report either way. This applies to the first 10 Launch Checks bought after October 30, 2026.

A different error?

Describe it and get a written quote

Send the error and what you were doing. You get a written scope, a fixed price and a timeline; Simon replies by email, usually within one business day.