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

  1. Rebuild with a matching SDK so the loader and native bundles agree on the InternalExchange array contract.
  2. If hosting manually, forward the exact internals array produced by the runtime loader verbatim, not a wrapped object.
  3. 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

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


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