dotnet/runtime · error · Error

Using node without crypto support. To enable current…

Error message

Using node without crypto support. To enable current operation, either provide polyfill for 'globalThis.crypto.getRandomValues' or enable 'node:crypto' module.

What it means

initPolyfillsEarly() under Node tries to import('node:crypto'). If that import fails (Node built without OpenSSL, a bundled runtime without the crypto module, or an opaque sandbox blocking dynamic import) it installs a stub for globalThis.crypto.getRandomValues that throws this message when called. The throw is deferred until something actually requests random bytes — typically integrity check, GUID, or TLS within the runtime.

Solutions

  1. Use a standard Node.js distribution that includes crypto (node:crypto is built-in).
  2. Provide a polyfill: set globalThis.crypto.getRandomValues to a function that fills the buffer from a CSPRNG before bootstrapping the loader.
  3. If using a bundler, mark node:crypto as external so the dynamic import resolves at runtime.
  4. Disable integrity checks (loaderConfig.disableIntegrityCheck=true) if randomness is only consumed by SRI — but other runtime paths still need getRandomValues.

Example fix

// before: node:crypto blocked, getRandomValues throws on first use

// after: provide polyfill before createDotnetRuntime
import { webcrypto } from 'node:crypto';
globalThis.crypto = webcrypto as any;
await dotnet.create();
Defensive patterns

Strategy: validation

Validate before calling

function hasCryptoRandom(): boolean {
  return typeof (globalThis as any).crypto?.getRandomValues === 'function';
}
if (!hasCryptoRandom()) {
  // install polyfill before bootstrapping
}

Type guard

function hasWebCrypto(): boolean {
  const c = (globalThis as any).crypto;
  return !!c && typeof c.getRandomValues === 'function';
}

Try / catch

try { await dotnet.create(); } catch (e) {
  if (/crypto support/.test((e as Error).message)) {
    const { webcrypto } = await import('node:crypto');
    (globalThis as any).crypto = webcrypto;
    await dotnet.create();
  } else throw e;
}

Prevention

When it happens

Trigger: Running the WASM loader in a Node build that excluded the crypto module (e.g. custom NodeJS build, Electron with --disable-crypto). Sandboxed environments (Cloudflare Workers in Node-compat mode, certain bundlers) that block dynamic import of node:crypto. Node compiled with --without-ssl.

Common situations: Electron main process with a stripped Node. Bun/Deno emulating Node where node:crypto import is partial. A bundler (webpack) that statically resolves the dynamic import to nothing. Container image with a minimal Node that lacks openssl.

Related errors


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

Appendix: source

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

        }
    }
    if (ENVIRONMENT_IS_NODE) {
        if (!globalThis.crypto) {
            globalThis.crypto = <any>{};
        }
        if (!globalThis.crypto.getRandomValues) {
            let nodeCrypto: any = undefined;
            try {
                // eslint-disable-next-line @typescript-eslint/ban-ts-comment
                // @ts-ignore:
                nodeCrypto = await import(/*! webpackIgnore: true */"node:crypto");
            } catch (err: any) {
                // Noop, error throwing polyfill provided bellow
            }

            if (!nodeCrypto) {
                globalThis.crypto.getRandomValues = () => {
                    throw new Error("Using node without crypto support. To enable current operation, either provide polyfill for 'globalThis.crypto.getRandomValues' or enable 'node:crypto' module.");
                };
            } else if (nodeCrypto.webcrypto) {
                globalThis.crypto = nodeCrypto.webcrypto;
            } else if (nodeCrypto.randomBytes) {
                const getRandomValues = (buffer: Uint8Array) => {
                    if (buffer) {
                        buffer.set(nodeCrypto.randomBytes(buffer.length));
                    }
                };
                globalThis.crypto.getRandomValues = getRandomValues as any;
            }
        }
        if (!globalThis.performance) {
            // eslint-disable-next-line @typescript-eslint/ban-ts-comment
            // @ts-ignore:
            globalThis.performance = (await import(/*! webpackIgnore: true */"perf_hooks")).performance;
        }
    }

View on GitHub (pinned to 60108ba66e)