{"record":{"id":"ac1edc9ddd393186","repo":"dotnet/runtime","slug":"native-module-already-loaded","errorCode":null,"errorMessage":"Native module already loaded","messagePattern":"Native module already loaded","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/native/libs/System.Native.Browser/libSystem.Native.Browser.extpost.js","lineNumber":9,"sourceCode":"//\n// Licensed to the .NET Foundation under one or more agreements.\n// The .NET Foundation licenses this file to you under the MIT license.\n\n/* eslint-disable no-undef */\n/* eslint-disable @typescript-eslint/no-unused-vars */\nvar fetch = fetch || undefined; var dotnetNativeModuleLoaded = false; var dotnetInternals = null;\nexport function dotnetInitializeModule(internals) {\n    if (dotnetNativeModuleLoaded) throw new Error(\"Native module already loaded\");\n    dotnetNativeModuleLoaded = true;\n    if (!Array.isArray(internals)) throw new Error(\"Expected internals to be an array\");\n    dotnetInternals = internals;\n    const runtimeApi = internals[0/*InternalExchangeIndex.RuntimeAPI*/];\n    if (typeof runtimeApi !== \"object\") throw new Error(\"Expected internals to have RuntimeAPI\");\n    if (typeof runtimeApi.Module !== \"object\") throw new Error(\"Expected internals to have Module\");\n    return createDotnetRuntime(runtimeApi.Module);\n}\n","sourceCodeStart":1,"sourceCodeEnd":18,"githubUrl":"https://github.com/dotnet/runtime/blob/290d5ab72cc1102813fbc0406fb186ceadabc340/src/native/libs/System.Native.Browser/libSystem.Native.Browser.extpost.js#L1-L18","documentation":"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.","triggerScenarios":"Calling dotnet.create() (or the underlying dotnetInitializeModule) a second time in the same page/process, or importing/bootstrapping the runtime module twice.","commonSituations":"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.","solutions":["Initialize the runtime exactly once, guarded by a module-level singleton flag.","Reuse the existing runtime instance across components instead of re-creating it.","Exclude the runtime bootstrap from HMR / StrictMode double-invoke."],"exampleFix":"// before: effect boots the runtime on every mount (StrictMode fires twice)\nuseEffect(() => { dotnet.create(); }, []);\n// after: cache the promise so init runs once\nlet runtimePromise;\nfunction getRuntime() {\n  if (!runtimePromise) runtimePromise = dotnet.create();\n  return runtimePromise;\n}\nuseEffect(() => { getRuntime(); }, []);","handlingStrategy":"validation","validationCode":"// Cache the runtime bootstrap so init runs exactly once\nlet runtimePromise;\nfunction getRuntime() {\n  if (!runtimePromise) runtimePromise = dotnet.create();\n  return runtimePromise;\n}\n// all callers: await getRuntime();","typeGuard":null,"tryCatchPattern":"try { await getRuntime(); }\ncatch (e) {\n  if (/Native module already loaded/.test(String(e.message))) {\n    // ignore: a concurrent caller already booted the runtime\n    return getRuntime();\n  }\n  throw e;\n}","preventionTips":["Bootstrap the runtime through a single cached promise so repeated callers share one init.","Exclude the bootstrap from React StrictMode double-invoke and HMR re-runs.","Do not call dotnet.create() from multiple components independently."],"tags":["initialization","singleton","lifecycle"],"analyzedSha":"290d5ab72cc1102813fbc0406fb186ceadabc340","analyzedAt":"2026-08-06T19:57:01.276Z","schemaVersion":2},"datasetVersion":"2026-08-06T23:17:07.152Z"}