dotnet/runtime · error · Error

No fetch implementation available

Error message

No fetch implementation available

What it means

fetchLike() walks three fallbacks: Node fs (only for file://), globalThis.fetch (browser/Node 18+), and a global read() function (shell/emscripten FS). If none apply, it throws 'No fetch implementation available'. This is a hard environment-incompatibility error: the host cannot make HTTP requests at all, so no asset can be downloaded.

Solutions

  1. Install and assign globalThis.fetch before bootstrap: import fetch from 'node-fetch'; globalThis.fetch = fetch as any; (Node <18).
  2. Upgrade to Node 18+ which has native global fetch.
  3. If in a shell/emscripten host, ensure the global read() function is exposed.
  4. If you supply a custom loader via loadBootResourceCallback, that bypasses fetchLike entirely — return Response objects from it.

Example fix

// before: Node 16, no fetch
const runtime = await dotnet.create(); // throws

// after
import fetch from 'node-fetch';
(globalThis as any).fetch = fetch;
const runtime = await dotnet.create();
Defensive patterns

Strategy: validation

Validate before calling

function hasFetch(): boolean {
  return typeof (globalThis as any).fetch === 'function'
      || typeof (globalThis as any).read === 'function';
}
if (!hasFetch()) {
  // install node-fetch or upgrade Node
}

Type guard

function hasFetchImpl(): boolean {
  return typeof (globalThis as any).fetch === 'function';
}

Try / catch

try { await dotnet.create(); } catch (e) {
  if (/No fetch implementation/.test((e as Error).message)) {
    const fetch = (await import('node-fetch')).default;
    (globalThis as any).fetch = fetch;
    await dotnet.create();
  } else throw e;
}

Prevention

When it happens

Trigger: Running the loader in a JS runtime with no fetch and no read() (e.g. an old Node <18 without a fetch polyfill, a minimal V8 isolate, or a custom host that exports neither). Node without setting globalThis.fetch and with a non-file:// URL (so the fs branch is skipped).

Common situations: Node 16 or earlier without node-fetch installed. Bun/Deno in Node-compat mode that hides globalThis.fetch. A bundled browser build that accidentally executes server-side before window.fetch exists. Tests in jsdom that forgot to install whatwg-fetch.

Related errors


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

Appendix: source

Thrown at src/native/libs/Common/JavaScript/loader/polyfills.ts:136

            const isText = expectedContentType && (expectedContentType.startsWith("application/json") || expectedContentType.startsWith("text/plain"));
            const arrayBuffer = read(url, isText ? "utf8" : "binary");
            return responseLike(url, arrayBuffer, {
                status: 200,
                statusText: "OK",
                headers: {
                    "Content-Length": isText ? arrayBuffer.length : arrayBuffer.byteLength.toString(),
                    "Content-Type": expectedContentType || "application/octet-stream"
                }
            });
        }
    } catch (e: any) {
        return responseLike(url, null, {
            status: 500,
            statusText: "ERR28: " + e,
            headers: {},
        });
    }
    throw new Error("No fetch implementation available");
}

export function responseLike(url: string, body: ArrayBuffer | string | null, options: ResponseInit): Response {
    if (typeof globalThis.Response === "function") {
        const response = new Response(body, options);

        // Best-effort alignment with the fallback object shape:
        // only define `url` if it does not already exist on the response.
        if (typeof (response as any).url === "undefined") {
            try {
                Object.defineProperty(response, "url", { value: url });
            } catch {
                // Ignore if the implementation does not allow redefining `url`
            }
        }

        return response;
    }

View on GitHub (pinned to 60108ba66e)