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_INTEROP: ${_ems_.DOTNET_INTEROP.gitHash} What it means
Thrown by dotnetInitializeModule when the loader-reported gitHash (runtimeApi.runtimeBuildInfo.gitHash) differs from the gitHash baked into the native interop module (_ems_.DOTNET_INTEROP.gitHash). The two halves of the runtime must be from the same build; a mismatch can cause ABI/protocol corruption, so initialization is aborted.
Source
Thrown at src/native/libs/System.Runtime.InteropServices.JavaScript.Native/native/index.ts:42
_ems_.dotnetRuntimeExports.resolveOrRejectPromise(args);
}
export function SystemInteropJS_CancelPromise(taskHolderGCHandle: GCHandle): void {
_ems_.dotnetRuntimeExports.cancelPromise(taskHolderGCHandle);
}
export function SystemInteropJS_InvokeJSFunction(functionJSSHandle: JSHandle, args: JSMarshalerArguments): void {
_ems_.dotnetRuntimeExports.invokeJSFunction(functionJSSHandle, args);
}
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_INTEROP.gitHash) {
throw new Error(`Mismatched git hashes between loader and runtime. Loader: ${runtimeApi.runtimeBuildInfo.gitHash}, DOTNET_INTEROP: ${_ems_.DOTNET_INTEROP.gitHash}`);
}
internals[InternalExchangeIndex.InteropJavaScriptExportsTable] = interopJavaScriptExportsToTable({
SystemInteropJS_GetManagedStackTrace: (args: JSMarshalerArguments) => _ems_._SystemInteropJS_GetManagedStackTrace(args),
SystemInteropJS_CallDelegate: (args: JSMarshalerArguments) => _ems_._SystemInteropJS_CallDelegate(args),
SystemInteropJS_CompleteTask: (args: JSMarshalerArguments) => _ems_._SystemInteropJS_CompleteTask(args),
SystemInteropJS_ReleaseJSOwnedObjectByGCHandle: (args: JSMarshalerArguments) => _ems_._SystemInteropJS_ReleaseJSOwnedObjectByGCHandle(args),
SystemInteropJS_BindAssemblyExports: (args: JSMarshalerArguments) => _ems_._SystemInteropJS_BindAssemblyExports(args),
SystemInteropJS_CallJSExport: (methodHandle: CSFnHandle, args: JSMarshalerArguments) => _ems_._SystemInteropJS_CallJSExport(methodHandle, args),
});
function interopJavaScriptExportsToTable(map: InteropJavaScriptExports): InteropJavaScriptExportsTable {
// keep in sync with interopJavaScriptExportsFromTable()
return [
map.SystemInteropJS_GetManagedStackTrace,
map.SystemInteropJS_CallDelegate,
map.SystemInteropJS_CompleteTask,
map.SystemInteropJS_ReleaseJSOwnedObjectByGCHandle,
map.SystemInteropJS_BindAssemblyExports,View on GitHub (pinned to 290d5ab72c)
Solutions
- Clean the publish/bin/wwwroot folder and republish from a single SDK so every runtime file matches.
- Bust the cache: append a version query string or update cache-control headers for runtime files.
- Confirm all runtime files come from the same NuGet package version (check locks/versions).
- The error prints both hashes; verify the loader hash matches the SDK you intend to ship.
Defensive patterns
Strategy: validation
Validate before calling
function assertMatchingGitHash(loaderHash: string, nativeHash: string) {
if (loaderHash && nativeHash && loaderHash !== nativeHash) {
throw new Error(`Loader/runtime git hash mismatch: ${loaderHash} vs ${nativeHash}`);
}
} Type guard
const gitHashesMatch = (a?: string, b?: string): boolean =>
!a || !b || a === b; Prevention
- Republish from a single SDK build; clean output dirs first.
- Bust CDN/browser cache for runtime files on every release.
- Lock all runtime NuGet packages to the same version; verify with the hashes printed in the error.
When it happens
Trigger: Serving dotnet.js from one build and dotnet.native.js / the interop library from another (e.g. CDN cached one file, local server served another). Upgrading the SDK but leaving a stale file in the publish output.
Common situations: CDN/edge cache serving mixed versions; partial publish; referencing runtime files via different package versions (Microsoft.NETCore.App etc.); CI artifact assembly mixing folders.
Related errors
- Expected internals to be an array
- Expected internals to have RuntimeAPI
- Mismatched git hashes between loader and runtime. Loader: ${
- Expected internals to be an array
- Expected internals to be an array
AI-assisted analysis of dotnet/runtime@290d5ab72c (2026-08-06).
Data as JSON: /api/errors/1d770f20d87d260e.
Report an issue: GitHub.