{"record":{"id":"1d770f20d87d260e","repo":"dotnet/runtime","slug":"mismatched-git-hashes-between-loader-and-runtime-1d770f","errorCode":null,"errorMessage":"Mismatched git hashes between loader and runtime. Loader: ${runtimeApi.runtimeBuildInfo.gitHash}, DOTNET_INTEROP: ${_ems_.DOTNET_INTEROP.gitHash}","messagePattern":"Mismatched git hashes between loader and runtime\\. Loader: (.+?), DOTNET_INTEROP: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"critical","filePath":"src/native/libs/System.Runtime.InteropServices.JavaScript.Native/native/index.ts","lineNumber":42,"sourceCode":"    _ems_.dotnetRuntimeExports.resolveOrRejectPromise(args);\n}\n\nexport function SystemInteropJS_CancelPromise(taskHolderGCHandle: GCHandle): void {\n    _ems_.dotnetRuntimeExports.cancelPromise(taskHolderGCHandle);\n}\n\nexport function SystemInteropJS_InvokeJSFunction(functionJSSHandle: JSHandle, args: JSMarshalerArguments): void {\n    _ems_.dotnetRuntimeExports.invokeJSFunction(functionJSSHandle, args);\n}\n\nexport const gitHash = GitHash;\nexport function dotnetInitializeModule(internals: InternalExchange): void {\n    if (!Array.isArray(internals)) throw new Error(\"Expected internals to be an array\");\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 !== _ems_.DOTNET_INTEROP.gitHash) {\n        throw new Error(`Mismatched git hashes between loader and runtime. Loader: ${runtimeApi.runtimeBuildInfo.gitHash}, DOTNET_INTEROP: ${_ems_.DOTNET_INTEROP.gitHash}`);\n    }\n\n    internals[InternalExchangeIndex.InteropJavaScriptExportsTable] = interopJavaScriptExportsToTable({\n        SystemInteropJS_GetManagedStackTrace: (args: JSMarshalerArguments) => _ems_._SystemInteropJS_GetManagedStackTrace(args),\n        SystemInteropJS_CallDelegate: (args: JSMarshalerArguments) => _ems_._SystemInteropJS_CallDelegate(args),\n        SystemInteropJS_CompleteTask: (args: JSMarshalerArguments) => _ems_._SystemInteropJS_CompleteTask(args),\n        SystemInteropJS_ReleaseJSOwnedObjectByGCHandle: (args: JSMarshalerArguments) => _ems_._SystemInteropJS_ReleaseJSOwnedObjectByGCHandle(args),\n        SystemInteropJS_BindAssemblyExports: (args: JSMarshalerArguments) => _ems_._SystemInteropJS_BindAssemblyExports(args),\n        SystemInteropJS_CallJSExport: (methodHandle: CSFnHandle, args: JSMarshalerArguments) => _ems_._SystemInteropJS_CallJSExport(methodHandle, args),\n    });\n    function interopJavaScriptExportsToTable(map: InteropJavaScriptExports): InteropJavaScriptExportsTable {\n        // keep in sync with interopJavaScriptExportsFromTable()\n        return [\n            map.SystemInteropJS_GetManagedStackTrace,\n            map.SystemInteropJS_CallDelegate,\n            map.SystemInteropJS_CompleteTask,\n            map.SystemInteropJS_ReleaseJSOwnedObjectByGCHandle,\n            map.SystemInteropJS_BindAssemblyExports,","sourceCodeStart":24,"sourceCodeEnd":60,"githubUrl":"https://github.com/dotnet/runtime/blob/60108ba66eb7d1d12f595480091b4ad80a24b172/src/native/libs/System.Runtime.InteropServices.JavaScript.Native/native/index.ts#L24-L60","documentation":"dotnetInitializeModule throws this when the loader's runtimeApi.runtimeBuildInfo.gitHash is non-empty AND differs from the git hash stamped into the runtime's DOTNET_INTEROP.gitHash. It is a build-consistency guard: the JS loader (dotnet.runtime.js / dotnet.native.js glue) and the managed runtime DLLs must come from the same build; otherwise marshaler tables, ABI offsets, and export names can mismatch and corrupt interop.","triggerScenarios":"Calling dotnet.create()/dotnetInitializeModule with a mix of artifacts from different dotnet wasm builds - e.g. a newer dotnet.runtime.js paired with an older dotnet.native.wasm/managed assemblies, or vice versa. Reached at native/index.ts:42 when both hashes are present and unequal.","commonSituations":"Caching/bundling only part of the runtime output after a `dotnet publish` (e.g. updating the JS bundle but keeping old wasm/bin). Copying dotnet.js from one SDK and the assemblies from another. CDN mismatch where the JS and the wasm are pinned to different versions.","solutions":["Republish and redeploy all runtime artifacts together from a single `dotnet publish` (or matching SDK build) so loader and runtime share a git hash.","Clear the browser/CDN cache of dotnet.runtime.js, dotnet.native.js, dotnet.native.wasm, and the managed DLLs, then reload.","Pin your CDN/bundle versions explicitly (e.g. https://my.cdn/dotnet/8.0.7/...) so JS and wasm never drift.","Verify by comparing the gitHash in the published dotnet.runtime.js header with the one reported by the runtime before boot."],"exampleFix":"// before: served mismatched files\n//   index.html -> dotnet.runtime.js (v8.0.7)\n//   bin/        -> assemblies from 8.0.4\n\n// after: redeploy from one publish\n//   dotnet new wasmbrowser -o app && dotnet publish app -c Release\n//   serve app/bin/Release/net8.0/browser-wasm/publish/ as a unit","handlingStrategy":"validation","validationCode":"// Before dotnet.create(), confirm the loader and runtime artifacts come from one build.\nasync function assertBuildConsistent() {\n  const loaderHash = (await import('consts:gitHash')).default; // stamped into loader bundle\n  // The runtime stamps its git hash onto DOTNET_INTEROP once booted; check after create()\n  // by reading runtimeApi.runtimeBuildInfo.gitHash and comparing to loaderHash.\n  return loaderHash; // compare post-boot; mismatch -> redeploy.\n}\n\n// In CI: pin all dotnet.* artifacts to the same version path on your CDN.","typeGuard":null,"tryCatchPattern":"try {\n  await dotnet.create();\n} catch (e) {\n  if (e instanceof Error && /Mismatched git hashes/i.test(e.message)) {\n    throw new Error('Redeploy all dotnet wasm artifacts from a single publish; clear CDN/browser cache.', { cause: e });\n  }\n  throw e;\n}","preventionTips":["Publish and serve the entire dotnet wasm output as one unit (dotnet.runtime.js, dotnet.native.*, managed DLLs).","Pin CDN paths to a specific SDK version so JS and wasm never drift.","Bust browser/CDN cache for all dotnet.* files at once after a rebuild."],"tags":["dotnet-wasm","build-consistency","version-mismatch","loader","critical"],"backgroundTag":null,"analyzedSha":"60108ba66eb7d1d12f595480091b4ad80a24b172","analyzedAt":"2026-08-10T18:54:11.478Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}