{"record":{"id":"49c999777bf9cffa","repo":"dotnet/runtime","slug":"mismatched-git-hashes-between-loader-and-runtime-49c999","errorCode":null,"errorMessage":"Mismatched git hashes between loader and runtime. Loader: ${runtimeApi.runtimeBuildInfo.gitHash}, Diagnostics: ${GitHash}","messagePattern":"Mismatched git hashes between loader and runtime\\. Loader: (.+?), Diagnostics: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"critical","filePath":"src/native/libs/System.Native.Browser/diagnostics/index.ts","lineNumber":26,"sourceCode":"\nimport { dotnetApi, dotnetUpdateInternals, dotnetUpdateInternalsSubscriber } from \"./cross-module\";\nimport { registerExit } from \"./exit\";\nimport { installNativeSymbols, symbolicateStackTrace } from \"./symbolicate\";\nimport { installLoggingProxy } from \"./console-proxy\";\nimport { collectMetrics } from \"./dotnet-counters\";\nimport { collectGcDump } from \"./dotnet-gcdump\";\nimport { collectCpuSamples } from \"./dotnet-cpu-profiler\";\nimport { 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\";\nimport { ds_rt_browser_performance_measure } from \"./browser-profiler\";\n\nexport function dotnetInitializeModule(internals: InternalExchange): void {\n    if (!Array.isArray(internals)) throw new Error(\"Expected internals to be an array\");\n\n    const runtimeApi = internals[InternalExchangeIndex.RuntimeAPI];\n    if (typeof runtimeApi !== \"object\") throw new Error(\"Expected internals to have RuntimeAPI\");\n\n    if (runtimeApi.runtimeBuildInfo.gitHash && runtimeApi.runtimeBuildInfo.gitHash !== GitHash) {\n        throw new Error(`Mismatched git hashes between loader and runtime. Loader: ${runtimeApi.runtimeBuildInfo.gitHash}, Diagnostics: ${GitHash}`);\n    }\n\n    internals[InternalExchangeIndex.DiagnosticsExportsTable] = diagnosticsExportsToTable({\n        symbolicateStackTrace,\n        installNativeSymbols,\n        ds_rt_websocket_create,\n        ds_rt_websocket_send,\n        ds_rt_websocket_poll,\n        ds_rt_websocket_recv,\n        ds_rt_websocket_close,\n        ds_rt_browser_performance_measure,\n    });\n    dotnetUpdateInternals(internals, dotnetUpdateInternalsSubscriber);\n\n    registerExit();\n    installLoggingProxy();\n    initializeDS();\n","sourceCodeStart":8,"sourceCodeEnd":44,"githubUrl":"https://github.com/dotnet/runtime/blob/60108ba66eb7d1d12f595480091b4ad80a24b172/src/native/libs/System.Native.Browser/diagnostics/index.ts#L8-L44","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Clear the browser/CDN cache and reload so all dotnet.*.js files and the .wasm come from the same deploy.","Rebuild the whole solution from a clean checkout so the loader, runtime, and diagnostics bundles share one git hash.","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.","If intentionally cross-loading builds during development, confirm both halves are from the same source commit before reporting a bug."],"exampleFix":"// before: mixing files\ndotnet.create({ /* loads runtime from build A */ });\n// + diagnostics.js left over from build B in wwwroot\n\n// after: single clean publish\n// rm -rf bin/ obj/ wwwroot/_framework/\n// dotnet publish -c Release\n// redeploy the entire _framework folder together","handlingStrategy":"validation","validationCode":"// Compare build hashes before handing internals to the diagnostics module.\nimport GitHash from \"consts:gitHash\";\n\nfunction assertBuildMatches(runtimeApi: any) {\n  const loader = runtimeApi?.runtimeBuildInfo?.gitHash;\n  if (loader && loader !== GitHash) {\n    throw new Error(`Refusing to init: loader=${loader} diagnostics=${GitHash}. Redeploy a consistent build.`);\n  }\n}","typeGuard":"null","tryCatchPattern":"null","preventionTips":["Deploy the entire _framework folder from a single publish; never mix files across SDK versions.","Cache-bust (hash/fingerprint) dotnet.*.js assets so stale bundles cannot be served.","After deploy, diff the gitHash reported by each support module to confirm they agree.","Keep one consistent workload/SDK version across build, CI, and deploy."],"tags":["git-hash","build-integrity","diagnostics","version-mismatch"],"backgroundTag":null,"analyzedSha":"60108ba66eb7d1d12f595480091b4ad80a24b172","analyzedAt":"2026-08-10T18:54:11.478Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}