dotnet/runtime · critical · Error
Expected internals to be an array
Error message
Expected internals to be an array
What it means
The System.Native.Browser native module's dotnetInitializeModule first asserts that internals is an array. The runtime exchanges data with native libraries through a positional InternalExchange array, so a non-array means the loader/native contract is broken before any export can be registered.
Source
Thrown at src/native/libs/System.Native.Browser/native/index.ts:19
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
import type { InternalExchange, NativeBrowserExports, NativeBrowserExportsTable } from "../types";
import { InternalExchangeIndex } from "../types";
import { _ems_ } from "../../Common/JavaScript/ems-ambient";
import GitHash from "consts:gitHash";
export { SystemJS_RandomBytes } from "./crypto";
export { SystemJS_GetLocaleInfo } from "./globalization-locale";
export { SystemJS_RejectMainPromise, SystemJS_ResolveMainPromise, SystemJS_MarkAsyncMain, SystemJS_ConsoleClear } from "./main";
export { SystemJS_ScheduleTimer, SystemJS_ScheduleBackgroundJob, SystemJS_ScheduleFinalization, SystemJS_ScheduleDiagnosticServer } from "./scheduling";
export { ds_rt_websocket_close, ds_rt_websocket_create, ds_rt_websocket_poll, ds_rt_websocket_recv, ds_rt_websocket_send, ds_rt_browser_performance_measure } from "./diagnostics";
export const gitHash = GitHash;
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 !== _ems_.DOTNET.gitHash) {
throw new Error(`Mismatched git hashes between loader and runtime. Loader: ${runtimeApi.runtimeBuildInfo.gitHash}, DOTNET: ${_ems_.DOTNET.gitHash}`);
}
internals[InternalExchangeIndex.NativeBrowserExportsTable] = nativeBrowserExportsToTable({
getWasmMemory,
getWasmTable,
SystemJS_ScheduleDiagnosticServer: _ems_._SystemJS_ScheduleDiagnosticServer,
SystemJS_GetMethodName: (pMethodDesc: number) => _ems_._SystemJS_GetMethodName(pMethodDesc),
});
_ems_.dotnetUpdateInternals(internals, _ems_.dotnetUpdateInternalsSubscriber);
setupEmscripten();
View on GitHub (pinned to 290d5ab72c)
Solutions
- Rebuild with a matching SDK so the loader and native bundles agree on the InternalExchange array contract.
- If hosting manually, forward the exact internals array produced by the runtime loader verbatim, not a wrapped object.
- Clear cached stale bundles and redeploy.
Example fix
// before
dotnetInitializeModule({ runtime: runtimeApi }) // object, not array
// after
dotnetInitializeModule([runtimeApi, /* other slots */]) Defensive patterns
Strategy: type-guard
Validate before calling
if (!Array.isArray(internals)) throw new TypeError("internals must be an array");
dotnetInitializeModule(internals); Type guard
const isInternalExchange = (x): x is any[] => Array.isArray(x);
Prevention
- Never wrap the internals array; forward it verbatim from the runtime loader.
- Pin all dotnet bundles to one build/SDK version.
When it happens
Trigger: dotnetInitializeModule receives a non-array (an object, undefined, or null) — a loader passing a different exchange shape than the positional array the native module expects.
Common situations: Mismatched loader/native bundle versions; a hand-written host that wraps internals in an object instead of forwarding the raw array; a corrupted/renamed bundle.
Related errors
- Expected internals to have RuntimeAPI
- Expected internals to have RuntimeAPI
- Expected internals to be an array
- Expected internals to have RuntimeAPI
- Expected internals to be an array
AI-assisted analysis of dotnet/runtime@290d5ab72c (2026-08-06).
Data as JSON: /api/errors/961d2db53790bdd0.
Report an issue: GitHub.