dotnet/runtime · error · Error
Failed to load resource '${asset.name}' from '${asset.resolv
Error message
Failed to load resource '${asset.name}' from '${asset.resolvedUrl}' after multiple attempts. Last HTTP status: ${response.status} ${response.statusText} What it means
loadResourceRetry tries an asset up to three times (initial + 2 retries, with a 100ms backoff and a 429-specific delay). If the final response is still not ok and its status is not in noRetryStatusCodes (400,401,403,404,405,406,409,410,411,413,414,415,422,426,501,505), it throws this final-after-retries error.
Source
Thrown at src/native/libs/Common/JavaScript/loader/assets.ts:426
}
// second attempt only after all first attempts are queued
await allDownloadsQueuedPCS.promise;
if (response.status === 429) {
// Too Many Requests
await delay(100);
}
dotnetLogger.debug(`Retrying download '${asset.name}'`);
response = await loadResourceAttempt();
if (response.ok || noRetryStatusCodes.has(response.status)) {
return response;
}
await delay(100); // wait 100ms before the last retry
dotnetLogger.debug(`Retrying download (2) '${asset.name}' after delay`);
response = await loadResourceAttempt();
if (response.ok) {
return response;
}
throw new Error(`Failed to load resource '${asset.name}' from '${asset.resolvedUrl}' after multiple attempts. Last HTTP status: ${response.status} ${response.statusText}`);
async function loadResourceAttempt(): Promise<Response> {
let response: Response;
try {
response = await loadResourceThrottle(asset);
if (!response) {
response = responseLike(asset.resolvedUrl!, null, {
status: 404,
statusText: "No response",
});
}
} catch (err: any) {
response = responseLike(asset.resolvedUrl!, null, {
status: 500,
statusText: err.message || "Exception during fetch",
});
}
return response;View on GitHub (pinned to 290d5ab72c)
Solutions
- Inspect the Last HTTP status in the message — 502/503/504 indicates upstream server/CDN problems; 429 indicates rate limiting.
- For 429, raise server-side rate limits or stagger asset requests (lower maxParallelDownloads in loaderConfig).
- For 502/503/504, verify backend health and increase uptime/restart capacity; retry loading the page once the backend recovers.
- If you control the server, ensure all framework assets return 200 reliably and consider a CDN with longer cache TTLs.
Example fix
// before
builder.withConfig({ maxParallelDownloads: 64 }); // overwhelms server → 429s
// after
builder.withConfig({ maxParallelDownloads: 4 }); // gentler ramp, avoids 429 retries Defensive patterns
Strategy: retry
Validate before calling
// Probe server stability before starting
const codes = await Promise.all([1,2,3].map(() => fetch(base).then(r => r.status).catch(() => 0)));
if (codes.some(c => c >= 500)) console.warn('Backend unstable; expect retry exhaustion'); Try / catch
try { await loadAll(); }
catch (err) {
if (/after multiple attempts/.test(err.message)) {
// exponential backoff then reload the page / re-run create()
await delay(1000); location.reload();
} else throw err;
} Prevention
- Keep maxParallelDownloads modest to avoid 429 storms.
- Monitor backend 5xx rates; alert before they reach end users.
- Use a CDN with aggressive caching to reduce origin load.
When it happens
Trigger: A retriable HTTP status (500, 502, 503, 504, 429, or transient 200-less failures) persisted across all three attempts. Permanent statuses (4xx listed above) return immediately without this message.
Common situations: Server/CDN instability; rate limiting (429) that the 100ms delay did not absorb; backend overload during a cold start; flaky reverse proxy returning 502/504; deployment in progress causing transient 500s.
Related errors
- Please install `node-fetch` and `node-abort-controller` npm
- This browser doesn't support fetch API. Please use a modern
- BrowserHttpWriteStream.Rejected
- OperationCanceledException
- Failed to load resource '${asset.name}' from '${asset.resolv
AI-assisted analysis of dotnet/runtime@290d5ab72c (2026-08-06).
Data as JSON: /api/errors/2f0d1e122c8a2e84.
Report an issue: GitHub.