mrdoob/three.js · error · HttpError

fetch for "${response.url}" responded with ${response.status

Error message

fetch for "${response.url}" responded with ${response.status}: ${response.statusText}

What it means

Thrown by FileLoader when the underlying fetch resolves with an HTTP status other than 200 (and not the special status 0 used for file:// and data:// protocols). The error is an HttpError carrying the original Response object so callers can inspect status, headers, and body. It signals the remote resource exists at the URL level but the server refused/failed to serve it.

Source

Thrown at src/loaders/FileLoader.js:220

									}

								}, ( e ) => {

									controller.error( e );

								} );

							}

						}

					} );

					return new Response( stream );

				} else {

					throw new HttpError( `fetch for "${response.url}" responded with ${response.status}: ${response.statusText}`, response );

				}

			} )
			.then( response => {

				switch ( responseType ) {

					case 'arraybuffer':

						return response.arrayBuffer();

					case 'blob':

						return response.blob();

					case 'document':

View on GitHub (pinned to da05705fa3)

Solutions

  1. Open the URL directly in a browser/Postman and confirm it returns 200; check the status code in the message.
  2. Verify the path and base URL are correct (absolute vs relative, leading slash, public/ vs assets/ folder).
  3. For 401/403, set loader.setWithCredentials(true) and/or supply the required Authorization header via request headers.
  4. For 5xx, implement retry with backoff; for 404, fix or remove the missing asset reference.
  5. Handle CORS: ensure the server sends Access-Control-Allow-Origin for cross-origin requests.

Example fix

// before: only success handler, errors are uncaught
loader.load(url, onLoad);

// after: supply an onError callback (or await loadAsync in try/catch)
loader.load(url, onLoad, onProgress, (err) => {
  console.error('Load failed:', err.message); // includes status + url
});
// or
try { const data = await loader.loadAsync(url); }
catch (e) { console.error(e.message, e.response?.status); }
Defensive patterns

Strategy: retry

Validate before calling

async function assertReachable(url, options = {}) {
  const res = await fetch(url, { method: 'HEAD', ...options });
  if (res.status !== 200 && res.status !== 0) {
    throw new Error(`${url} unreachable: ${res.status}`);
  }
  return true;
}

await assertReachable(url);

Try / catch

async function loadWithRetry(loader, url, retries = 3) {
  for (let attempt = 1; attempt <= retries; attempt++) {
    try {
      return await loader.loadAsync(url);
    } catch (e) {
      const status = e.response?.status;
      if (attempt === retries || (status && status < 500)) throw e;
      await new Promise(r => setTimeout(r, 2 ** attempt * 200));
    }
  }
}

Prevention

When it happens

Trigger: Calling loader.load(url, onLoad, onProgress, onError) or loadAsync(url) where the server returns 404, 403, 401, 500, 502, 503, etc. Also a wrong/mistyped URL, a missing asset path, an expired/signed S3 URL, or a CDN returning an error page. CORS preflight failures sometimes surface here too.

Common situations: Deploying with incorrect base/asset paths. Hot-reload pointing at a moved file. Rate-limited or temporarily down CDN. Authenticated endpoint missing credentials/tokens. Behind a reverse proxy returning HTML error pages for missing routes.

Related errors


AI-assisted analysis of mrdoob/three.js@da05705fa3 (2026-08-12). Data as JSON: /api/errors/8dbd7ceeb27ab76d. Report an issue: GitHub.