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}, Diagnostics: ${GitHash}

What it means

The Diagnostics module (System.Native.Browser/diagnostics) embeds a git commit hash at build time via `consts:gitHash`. During dotnetInitializeModule() it compares that baked hash against runtimeApi.runtimeBuildInfo.gitHash supplied by the loader. A mismatch means the diagnostics JS bundle and the .NET runtime/WASM were produced by different builds and are ABI-incompatible.

Solutions

  1. Clear the browser/CDN cache and reload so all dotnet.*.js files and the .wasm come from the same deploy.
  2. Rebuild the whole solution from a clean checkout so the loader, runtime, and diagnostics bundles share one git hash.
  3. Ensure your publish/copy step does not mix files from different dotnet SDK/workload versions; use one consistent Microsoft.NET.Sdk.Web or Microsoft.NET.Workload.WebAssembly package set.
  4. If intentionally cross-loading builds during development, confirm both halves are from the same source commit before reporting a bug.

Example fix

// before: mixing files
dotnet.create({ /* loads runtime from build A */ });
// + diagnostics.js left over from build B in wwwroot

// after: single clean publish
// rm -rf bin/ obj/ wwwroot/_framework/
// dotnet publish -c Release
// redeploy the entire _framework folder together
Defensive patterns

Strategy: validation

Validate before calling

// Compare build hashes before handing internals to the diagnostics module.
import GitHash from "consts:gitHash";

function assertBuildMatches(runtimeApi: any) {
  const loader = runtimeApi?.runtimeBuildInfo?.gitHash;
  if (loader && loader !== GitHash) {
    throw new Error(`Refusing to init: loader=${loader} diagnostics=${GitHash}. Redeploy a consistent build.`);
  }
}

Type guard

null

Try / catch

null

Prevention

When it happens

Trigger: Loading a dotnet.runtime.js (loader) from one build together with a diagnostics support bundle compiled from a different commit. runtimeBuildInfo.gitHash is non-empty and differs from the Diagnostics module's baked GitHash.

Common situations: Mixing a NuGet package's runtime bits with locally rebuilt diagnostics JS; partial publish where some static assets are cached from an older deploy; CI producing the runtime and the support JS in separate jobs that drifted; browser cache serving stale dotnet.js while the WASM is fresh.

Related errors


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

Appendix: source

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

import { dotnetApi, dotnetUpdateInternals, dotnetUpdateInternalsSubscriber } from "./cross-module";
import { registerExit } from "./exit";
import { installNativeSymbols, symbolicateStackTrace } from "./symbolicate";
import { installLoggingProxy } from "./console-proxy";
import { collectMetrics } from "./dotnet-counters";
import { collectGcDump } from "./dotnet-gcdump";
import { collectCpuSamples } from "./dotnet-cpu-profiler";
import { connectDSRouter, ds_rt_websocket_close, ds_rt_websocket_create, ds_rt_websocket_poll, ds_rt_websocket_recv, ds_rt_websocket_send, initializeDS } from "./diagnostic-server";
import { ds_rt_browser_performance_measure } from "./browser-profiler";

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}, Diagnostics: ${GitHash}`);
    }

    internals[InternalExchangeIndex.DiagnosticsExportsTable] = diagnosticsExportsToTable({
        symbolicateStackTrace,
        installNativeSymbols,
        ds_rt_websocket_create,
        ds_rt_websocket_send,
        ds_rt_websocket_poll,
        ds_rt_websocket_recv,
        ds_rt_websocket_close,
        ds_rt_browser_performance_measure,
    });
    dotnetUpdateInternals(internals, dotnetUpdateInternalsSubscriber);

    registerExit();
    installLoggingProxy();
    initializeDS();

View on GitHub (pinned to 60108ba66e)