dotnet/runtime · error · Error

Native module already loaded

Error message

Native module already loaded

What it means

Thrown by libSystem.Native.Browser.extpost.js's dotnetInitializeModule when dotnetNativeModuleLoaded is already true. The native module is a singleton that may be initialized only once per page load; a second init attempt indicates the runtime bootstrap was invoked twice.

Source

Thrown at src/native/libs/System.Native.Browser/libSystem.Native.Browser.extpost.js:9

//
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

/* eslint-disable no-undef */
/* eslint-disable @typescript-eslint/no-unused-vars */
var fetch = fetch || undefined; var dotnetNativeModuleLoaded = false; var dotnetInternals = null;
export function dotnetInitializeModule(internals) {
    if (dotnetNativeModuleLoaded) throw new Error("Native module already loaded");
    dotnetNativeModuleLoaded = true;
    if (!Array.isArray(internals)) throw new Error("Expected internals to be an array");
    dotnetInternals = internals;
    const runtimeApi = internals[0/*InternalExchangeIndex.RuntimeAPI*/];
    if (typeof runtimeApi !== "object") throw new Error("Expected internals to have RuntimeAPI");
    if (typeof runtimeApi.Module !== "object") throw new Error("Expected internals to have Module");
    return createDotnetRuntime(runtimeApi.Module);
}

View on GitHub (pinned to 290d5ab72c)

Solutions

  1. Initialize the runtime exactly once, guarded by a module-level singleton flag.
  2. Reuse the existing runtime instance across components instead of re-creating it.
  3. Exclude the runtime bootstrap from HMR / StrictMode double-invoke.

Example fix

// before: effect boots the runtime on every mount (StrictMode fires twice)
useEffect(() => { dotnet.create(); }, []);
// after: cache the promise so init runs once
let runtimePromise;
function getRuntime() {
  if (!runtimePromise) runtimePromise = dotnet.create();
  return runtimePromise;
}
useEffect(() => { getRuntime(); }, []);
Defensive patterns

Strategy: validation

Validate before calling

// Cache the runtime bootstrap so init runs exactly once
let runtimePromise;
function getRuntime() {
  if (!runtimePromise) runtimePromise = dotnet.create();
  return runtimePromise;
}
// all callers: await getRuntime();

Try / catch

try { await getRuntime(); }
catch (e) {
  if (/Native module already loaded/.test(String(e.message))) {
    // ignore: a concurrent caller already booted the runtime
    return getRuntime();
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling dotnet.create() (or the underlying dotnetInitializeModule) a second time in the same page/process, or importing/bootstrapping the runtime module twice.

Common situations: React StrictMode double-invoking an effect that boots the runtime; Vite/webpack HMR re-running the bootstrap; two components each calling dotnet.create(); a retry path that re-inits after a partial failure.

Related errors


AI-assisted analysis of dotnet/runtime@290d5ab72c (2026-08-06). Data as JSON: /api/errors/ac1edc9ddd393186. Report an issue: GitHub.