dotnet/runtime · critical · Error

Mismatched git hashes between loader and runtime. Loader

Error message

Mismatched git hashes between loader and runtime. Loader: ${runtimeApi.runtimeBuildInfo.gitHash}, DOTNET: ${_ems_.DOTNET.gitHash}

What it means

The Native module (System.Native.Browser/native) verifies during dotnetInitializeModule() that the loader-supplied runtimeBuildInfo.gitHash matches _ems_.DOTNET.gitHash (the hash baked into the core runtime bundle). A mismatch means the native-browser support JS was built from a different commit than the core .NET runtime.

Solutions

  1. Publish/copy the entire _framework (or equivalent) folder from one consistent build so all dotnet JS bundles share a git hash.
  2. Clear browser/CDN/proxy caches that may serve a mix of old and new JS.
  3. Rebuild from clean (rm -rf bin obj) to guarantee the workload stamps a single hash across all support modules.
  4. Verify the deployed dotnet.runtime.js, the native support JS, and the WASM all carry the same version metadata.

Example fix

// before: dotnet.runtime.js from SDK 8.0.x, System.Native support JS from 9.0.x

// after: single consistent workload publish
// dotnet workload restore
// dotnet publish -c Release  (copy whole _framework output)
Defensive patterns

Strategy: validation

Validate before calling

// Verify all support modules share the runtime's git hash before initializing.
function assertConsistentBuild(runtimeApi: any, nativeHash: string) {
  const loader = runtimeApi?.runtimeBuildInfo?.gitHash;
  if (loader && loader !== nativeHash) {
    throw new Error(`Build mismatch: loader=${loader} native=${nativeHash}. Redeploy consistently.`);
  }
}

Type guard

null

Try / catch

null

Prevention

When it happens

Trigger: dotnet.runtime.js (DOTNET bundle) and the System.Native native-support JS come from different builds; _ems_.DOTNET.gitHash is populated but differs from the loader-reported hash.

Common situations: Stale cached dotnet.*.js while the .wasm/runtime JS is refreshed; hand-assembled wwwroot mixing files from SDK versions; partial publish; dev workflow that rebuilds only one project.

Related errors


AI-assisted analysis of dotnet/runtime@60108ba66e (2026-08-10). Data as JSON: /api/errors/53a4f0abbfd8301b. Report an issue: GitHub.

Appendix: source

Thrown at src/native/libs/System.Native.Browser/native/index.ts:25

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();

    // eslint-disable-next-line @typescript-eslint/no-unused-vars
    function nativeBrowserExportsToTable(map: NativeBrowserExports): NativeBrowserExportsTable {
        // keep in sync with nativeBrowserExportsFromTable()
        return [
            map.getWasmMemory,
            map.getWasmTable,

View on GitHub (pinned to 60108ba66e)