{"record":{"id":"d1a1b1646cb571eb","repo":"dotnet/runtime","slug":"expected-internals-to-have-runtimeapi-d1a1b1","errorCode":null,"errorMessage":"Expected internals to have RuntimeAPI","messagePattern":"Expected internals to have RuntimeAPI","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"critical","filePath":"src/native/libs/System.Runtime.InteropServices.JavaScript.Native/interop/index.ts","lineNumber":33,"sourceCode":"import { initializeMarshalersToJs, resolveOrRejectPromise } from \"./marshal-to-js\";\nimport { initializeMarshalersToCs } from \"./marshal-to-cs\";\nimport { forceDisposeProxies, releaseCSOwnedObject } from \"./gc-handles\";\nimport { cancelPromise } from \"./cancelable-promise\";\nimport { loadLazyAssembly, loadSatelliteAssemblies } from \"./lazy\";\nimport { jsInteropState } from \"./marshal\";\nimport { initializeScheduling, abortInteropTimers } from \"./scheduling\";\nimport { wsAbort, wsClose, wsCreate, wsGetState, wsOpen, wsReceive, wsSend } from \"./web-socket\";\nimport {\n    httpSupportsStreamingRequest, httpSupportsStreamingResponse, httpCreateController, httpGetResponseType,\n    httpGetResponseStatus, httpAbort, httpTransformStreamWrite, httpTransformStreamClose, httpFetch,\n    httpFetchStream, httpFetchBytes, httpGetResponseHeaderNames, httpGetResponseHeaderValues, httpGetResponseBytes,\n    httpGetResponseLength, httpGetStreamedResponseBytes,\n} from \"./http\";\n\nexport function dotnetInitializeModule(internals: InternalExchange): void {\n    if (!Array.isArray(internals)) throw new Error(\"Expected internals to be an array\");\n    const runtimeApi = internals[InternalExchangeIndex.RuntimeAPI];\n    if (typeof runtimeApi !== \"object\") throw new Error(\"Expected internals to have RuntimeAPI\");\n\n    if (runtimeApi.runtimeBuildInfo.gitHash && runtimeApi.runtimeBuildInfo.gitHash !== GitHash) {\n        throw new Error(`Mismatched git hashes between loader and runtime. Loader: ${runtimeApi.runtimeBuildInfo.gitHash}, Runtime: ${GitHash}`);\n    }\n\n    const runtimeApiLocal: Partial<RuntimeAPI> = {\n        getAssemblyExports,\n        setModuleImports,\n    };\n    Object.assign(runtimeApi, runtimeApiLocal);\n    Object.assign(runtimeApi.INTERNAL, {\n        hasProperty,\n        getTypeOfProperty,\n        getProperty,\n        setProperty,\n        getGlobalThis,\n        getDotnetInstance,\n        dynamicImport,","sourceCodeStart":15,"sourceCodeEnd":51,"githubUrl":"https://github.com/dotnet/runtime/blob/290d5ab72cc1102813fbc0406fb186ceadabc340/src/native/libs/System.Runtime.InteropServices.JavaScript.Native/interop/index.ts#L15-L51","documentation":"The interop module reads internals[InternalExchangeIndex.RuntimeAPI] and asserts it is an object before attaching getAssemblyExports, setModuleImports, the INTERNAL API surface, and the RuntimeExportsTable. Without it, JS↔.NET marshaling cannot be initialized.","triggerScenarios":"internals is a valid array but the RuntimeAPI slot is undefined — the core runtime hasn't populated it yet, or InternalExchangeIndex values are misaligned due to a loader/interop version mismatch.","commonSituations":"Interop module initializing before the core runtime; version mismatch shifting InternalExchangeIndex values; partial cache serving an old interop bundle with a new runtime.","solutions":["Ensure the core runtime bundle loads and fills internals[InternalExchangeIndex.RuntimeAPI] before interop init.","Rebuild/republish all dotnet bundles from one SDK so InternalExchangeIndex values align.","Cache-bust all dotnet artifacts together."],"exampleFix":"// before: interop init before runtime fills the slot\n// internals[0] === undefined\ndotnetInitializeModule(internals);\n\n// after\nawait loadCoreRuntimeFirst(); // populates internals[0]\ndotnetInitializeModule(internals);","handlingStrategy":"type-guard","validationCode":"if (!Array.isArray(internals) || typeof internals[0] !== \"object\")\n  throw new Error(\"RuntimeAPI missing — load core runtime before interop\");\ndotnetInitializeModule(internals);","typeGuard":"const hasRuntimeApi = (x: any[]): x is any[] =>\n  Array.isArray(x) && typeof x[0] === \"object\" && x[0] !== null;","tryCatchPattern":null,"preventionTips":["Initialize the interop module only after the core runtime fills internals[0].","Keep the interop bundle and runtime from the same build."],"tags":["initialization","runtime-interop","internals"],"analyzedSha":"290d5ab72cc1102813fbc0406fb186ceadabc340","analyzedAt":"2026-08-06T19:57:01.276Z","schemaVersion":2},"datasetVersion":"2026-08-06T23:17:07.152Z"}