dotnet/runtime · critical · Error
Expected internals to have RuntimeAPI
Error message
Expected internals to have RuntimeAPI
What it means
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.
Source
Thrown at src/native/libs/System.Runtime.InteropServices.JavaScript.Native/interop/index.ts:33
import { initializeMarshalersToJs, resolveOrRejectPromise } from "./marshal-to-js";
import { initializeMarshalersToCs } from "./marshal-to-cs";
import { forceDisposeProxies, releaseCSOwnedObject } from "./gc-handles";
import { cancelPromise } from "./cancelable-promise";
import { loadLazyAssembly, loadSatelliteAssemblies } from "./lazy";
import { jsInteropState } from "./marshal";
import { initializeScheduling, abortInteropTimers } from "./scheduling";
import { wsAbort, wsClose, wsCreate, wsGetState, wsOpen, wsReceive, wsSend } from "./web-socket";
import {
httpSupportsStreamingRequest, httpSupportsStreamingResponse, httpCreateController, httpGetResponseType,
httpGetResponseStatus, httpAbort, httpTransformStreamWrite, httpTransformStreamClose, httpFetch,
httpFetchStream, httpFetchBytes, httpGetResponseHeaderNames, httpGetResponseHeaderValues, httpGetResponseBytes,
httpGetResponseLength, httpGetStreamedResponseBytes,
} from "./http";
export function dotnetInitializeModule(internals: InternalExchange): void {
if (!Array.isArray(internals)) throw new Error("Expected internals to be an array");
const runtimeApi = internals[InternalExchangeIndex.RuntimeAPI];
if (typeof runtimeApi !== "object") throw new Error("Expected internals to have RuntimeAPI");
if (runtimeApi.runtimeBuildInfo.gitHash && runtimeApi.runtimeBuildInfo.gitHash !== GitHash) {
throw new Error(`Mismatched git hashes between loader and runtime. Loader: ${runtimeApi.runtimeBuildInfo.gitHash}, Runtime: ${GitHash}`);
}
const runtimeApiLocal: Partial<RuntimeAPI> = {
getAssemblyExports,
setModuleImports,
};
Object.assign(runtimeApi, runtimeApiLocal);
Object.assign(runtimeApi.INTERNAL, {
hasProperty,
getTypeOfProperty,
getProperty,
setProperty,
getGlobalThis,
getDotnetInstance,
dynamicImport,View on GitHub (pinned to 290d5ab72c)
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.
Example fix
// before: interop init before runtime fills the slot // internals[0] === undefined dotnetInitializeModule(internals); // after await loadCoreRuntimeFirst(); // populates internals[0] dotnetInitializeModule(internals);
Defensive patterns
Strategy: type-guard
Validate before calling
if (!Array.isArray(internals) || typeof internals[0] !== "object")
throw new Error("RuntimeAPI missing — load core runtime before interop");
dotnetInitializeModule(internals); Type guard
const hasRuntimeApi = (x: any[]): x is any[] => Array.isArray(x) && typeof x[0] === "object" && x[0] !== null;
Prevention
- Initialize the interop module only after the core runtime fills internals[0].
- Keep the interop bundle and runtime from the same build.
When it happens
Trigger: 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.
Common situations: Interop module initializing before the core runtime; version mismatch shifting InternalExchangeIndex values; partial cache serving an old interop bundle with a new runtime.
Related errors
- Expected internals to have RuntimeAPI
- Expected internals to be an array
- Expected internals to have RuntimeAPI
- Expected internals to be an array
- Expected internals to have RuntimeAPI
AI-assisted analysis of dotnet/runtime@290d5ab72c (2026-08-06).
Data as JSON: /api/errors/d1a1b1646cb571eb.
Report an issue: GitHub.