dotnet/runtime · error · Error

Failed to load resource

Error message

Failed to load resource '${asset.name}' from '${asset.resolvedUrl}': ${message}

What it means

Wrapped re-throw inside fetchBytes(): loadResource() rejected (network throw, abort, CORS, or an exception thrown by a custom loadBootResourceCallback). The wrapper strips the original .silent flag so the error propagates through exit listeners. Original cause is attached via { cause: err }. Asset bytes could not be obtained at all — no HTTP response was successfully produced.

Solutions

  1. Open DevTools Network tab and inspect the failing request's status/type; the original cause is in err.cause.
  2. If CORS, add Access-Control-Allow-Origin for the WASM app origin on the asset server, or host assets same-origin.
  3. If a custom loadBootResourceCallback throws, guard its body and return a valid Response or string URL.
  4. If SRI hash mismatch, rebuild so the boot manifest hash matches the published asset bytes.
  5. If offline/Node, ensure polyfills.ts nodeFs is initialized before fetch, or pass a globalThis.fetch.

Example fix

// before: custom loader throws on auth failure
options.loadBootResource = (type, name, url) => fetch(url); // rejects 401

// after: return a Response, handle auth
options.loadBootResource = (type, name, url, integrity, behavior) =>
  fetch(url, { credentials: 'include' });
Defensive patterns

Strategy: try-catch

Validate before calling

// Pre-flight the URL is reachable and CORS permits the origin
async function canFetchAsset(url: string): Promise<boolean> {
  try {
    const r = await fetch(url, { method: 'HEAD', mode: 'cors' });
    return r.ok || r.status === 405; // 405 = HEAD not allowed but resource exists
  } catch { return false; }
}

Type guard

function isResponseLike(v: unknown): v is Response {
  return !!v && typeof v === 'object' && typeof (v as any).arrayBuffer === 'function' && typeof (v as any).ok === 'boolean';
}

Try / catch

try {
  await dotnet.create();
} catch (e) {
  const cause = (e as Error)?.cause ?? e;
  if (/Failed to load resource/.test((e as Error).message)) {
    reportToUser('Asset download failed', { url: extractUrl(e), cause });
  }
  throw e;
}

Prevention

When it happens

Trigger: Network offline or DNS failure during assembly/PDB/ICU/VFS download. CORS preflight rejection blocking the fetch. A user-supplied loadBootResourceCallback that throws or returns a promise that rejects. TLS/cert error on the asset URL. Service Worker returning a rejecting Response promise.

Common situations: Running the WASM app from a different origin than the assets without CORS headers. Corporate proxy intercepting requests. Misconfigured CDN returning an opaque response. Custom loadBootResourceCallback returning fetch to a private endpoint that 401s and throws. file:// URLs in Node without the fs polyfill resolved. Asset hash mismatch triggers SRI failure (browser throws).

Related errors


AI-assisted analysis of dotnet/runtime@60108ba66e (2026-08-10). Data as JSON: /api/errors/5a98b6186140799a. Report an issue: GitHub.

Appendix: source

Thrown at src/native/libs/Common/JavaScript/loader/assets.ts:356

        }
        assetInternal.behavior = "symbols";
        assetInternal.isOptional = assetInternal.isOptional || loaderConfig.ignorePdbLoadErrors;
        tableText = await fetchText(assetInternal);
    } finally {
        onDownloadedAsset(assetInternal);
    }
    dotnetDiagnosticsExports.installNativeSymbols(tableText || "");
}

async function fetchBytes(asset: AssetEntryInternal): Promise<Uint8Array | null> {
    dotnetAssert.check(asset && asset.resolvedUrl, "Bad asset.resolvedUrl");
    let response: Response;
    try {
        response = await loadResource(asset);
    } catch (err: any) {
        // Strip .silent flag from download errors so they are properly reported via exit listeners
        const message = err instanceof Error ? err.message : String(err);
        throw new Error(`Failed to load resource '${asset.name}' from '${asset.resolvedUrl}': ${message}`, { cause: err });
    }
    if (!response.ok) {
        if (asset.isOptional) {
            dotnetLogger.warn(`Optional resource '${asset.name}' failed to load from '${asset.resolvedUrl}'. HTTP status: ${response.status} ${response.statusText}`);
            return null;
        }
        throw new Error(`Failed to load resource '${asset.name}' from '${asset.resolvedUrl}'. HTTP status: ${response.status} ${response.statusText}`);
    }
    const buffer = await (asset.buffer || response.arrayBuffer());
    return new Uint8Array(buffer);
}

async function fetchText(asset: AssetEntryInternal): Promise<string | null> {
    dotnetAssert.check(asset && asset.resolvedUrl, "Bad asset.resolvedUrl");
    let response: Response;
    try {
        response = await loadResource(asset);
    } catch (err: any) {

View on GitHub (pinned to 60108ba66e)