dotnet/aspnetcore · error · Error

There are multiple .NET runtimes present, so a default…

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() when defaultCallDispatcher is null, meaning attachDispatcher() was called more than once with different dispatchers. With multiple .NET runtimes loaded there is no single 'default' to route legacy static-style calls to, so the library refuses to guess. Callers must use a specific DotNetObject or dispatcher instance instead.

Solutions

  1. Use a DotNetObjectReference from .NET and call invokeMethodAsync on that specific instance instead of the module-level DotNet.invokeMethodAsync.
  2. Capture the specific ICallDispatcher returned by attachDispatcher and call invokeDotNetStaticMethodAsync on it.
  3. Reduce to a single Blazor runtime per page if possible.

Example fix

// before (ambiguous default)
DotNet.invokeMethodAsync('MyLib', 'DoThing');

// after (use the specific dispatcher / instance)
const dispatcher = DotNet.attachDispatcher(myDispatcher);
dispatcher.invokeDotNetStaticMethodAsync('MyLib', 'DoThing');
// or, from .NET, pass a DotNetObjectReference and call .invokeMethodAsync on it in JS
Defensive patterns

Strategy: validation

Validate before calling

// Use a specific dispatcher / instance instead of the module-level default.
const dispatcher = DotNet.attachDispatcher(myDispatcher);
await dispatcher.invokeDotNetStaticMethodAsync('MyLib', 'Method');
// or receive a DotNetObjectReference from .NET and call invokeMethodAsync on it.

Try / catch

try { return await DotNet.invokeMethodAsync('MyLib', 'Method'); } catch (e) { if (/multiple .NET runtimes/.test(e.message)) { console.error('Use a specific DotNetObjectReference or captured dispatcher.'); } throw e; }

Prevention

When it happens

Trigger: Loading two Blazor runtimes on the same page (e.g., two Blazor WebAssembly roots, or Blazor Server + Blazor WebAssembly), each calling attachDispatcher. Then calling DotNet.invokeMethod / invokeMethodAsync (the module-level legacy APIs) hits the null default.

Common situations: Embedding multiple Blazor components from different apps on one page; mixing Blazor WebAssembly and Blazor Server in a host shell; testing harness that loads the runtime twice.

Related errors


AI-assisted analysis of dotnet/aspnetcore@3600ca084e (2026-08-11). Data as JSON: /api/errors/249f71f05c9f3188. Report an issue: GitHub.

Appendix: 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 3600ca084e)