dotnet/aspnetcore · error
There are multiple .NET runtimes present, so a default dispa
Error message
There are multiple .NET runtimes present, so a default dispatcher could not be resolved. Use DotNetObject to invoke .NET instance methods.
What it means
Thrown by getDefaultCallDispatcher() in Microsoft.JSInterop.ts (line 257) when defaultCallDispatcher is explicitly null — set that way by attachDispatcher() the moment a SECOND dispatcher is registered. With multiple .NET runtimes present, there is no safe 'default', so the static invokeMethod/invokeMethodAsync APIs refuse to guess. The error directs you to use DotNetObject (instance references) which carry their own dispatcher binding.
Source
Thrown at src/JSInterop/Microsoft.JSInterop.JS/src/src/Microsoft.JSInterop.ts:257
currentCallDispatcher = callDispatcher;
const result = json ? JSON.parse(json, (key, initialValue) => {
// Invoke each reviver in order, passing the output from the previous reviver,
// so that each one gets a chance to transform the value
return jsonRevivers.reduce(
(latestValue, reviver) => reviver(key, latestValue),
initialValue
);
}) : null;
currentCallDispatcher = undefined;
return result;
}
function getDefaultCallDispatcher(): CallDispatcher {
if (defaultCallDispatcher === undefined) {
throw new Error("No call dispatcher has been set.");
} else if (defaultCallDispatcher === null) {
throw new Error("There are multiple .NET runtimes present, so a default dispatcher could not be resolved. Use DotNetObject to invoke .NET instance methods.");
} else {
return defaultCallDispatcher;
}
}
interface PendingAsyncCall<T> {
resolve: (value?: T | PromiseLike<T>) => void;
reject: (reason?: any) => void;
}
/**
* Represents the type of result expected from a JS interop call.
*/
// eslint-disable-next-line no-shadow
export enum JSCallResultType {
Default = 0,
JSObjectReference = 1,
JSStreamReference = 2,View on GitHub (pinned to 294cab2f9b)
Solutions
- Switch JS→.NET instance calls to use DotNetObjectReference: pass a [JSInvokable] object from .NET to JS and call invokeMethodAsync on that DotNetObject — it knows its own dispatcher.
- For static methods, route through a specific runtime's dispatcher object instead of the global default.
- If only one runtime is intended, ensure a second dispatcher is not being attached accidentally (double bootstrapping, stray script).
- Refactor interop so each call is bound to the runtime that owns the target object.
Example fix
// before — ambiguous with two runtimes
DotNet.invokeMethodAsync('MyAssembly', 'DoThing'); // throws
// after — instance-bound call
// C#: dotNetRef = DotNetObjectReference.Create(this); passed to JS
@code { [JSInvokable] public string DoThing() => "ok"; }
// JS:
dotNetRef.invokeMethodAsync('DoThing'); Defensive patterns
Strategy: type-guard
Type guard
function isDotNetObject(v: any): v is { invokeMethodAsync: (...args: any[]) => Promise<any> } {
return v && typeof v.invokeMethodAsync === 'function' && typeof v['_id'] !== 'undefined';
} Prevention
- Use DotNetObjectReference for instance calls in multi-runtime apps.
- Avoid static invokeMethodAsync when more than one runtime may attach.
- Bind each interop call to the runtime that owns the target.
- Verify you are not double-bootstrapping runtimes.
When it happens
Trigger: Two or more .NET runtimes call attachDispatcher() in the same page (e.g., a Blazor Server circuit and a Blazor WebAssembly runtime, or two wasm runtimes). After the second attaches, defaultCallDispatcher is nulled and any subsequent static invokeMethodAsync throws this message.
Common situations: Blazor Web App with both Server and WebAssembly interactive runtimes on the same page (InteractiveAuto during handoff, or custom multi-runtime hosting). Hosting two Blazor apps on one page. Custom runtime embedding that registers multiple dispatchers. Migrating from single to multi-runtime without switching JS interop calls to instance-based DotNetObjectReference.
Related errors
- Cannot create a JSObjectReference from the value '${jsObject
- Cannot create a JSStreamReference from the value '${streamRe
- Supplied value is not a typed array or blob.
- Cannot create a JSStreamReference from the value '${streamRe
- No call dispatcher has been set.
AI-assisted analysis of dotnet/aspnetcore@294cab2f9b (2026-08-06).
Data as JSON: /api/errors/249f71f05c9f3188.
Report an issue: GitHub.