dotnet/aspnetcore · critical · Error

No call dispatcher has been set.

Error message

No call dispatcher has been set.

What it means

Thrown by getDefaultCallDispatcher() when defaultCallDispatcher is still undefined, meaning DotNet.attachDispatcher() was never called. The default dispatcher is set by the Blazor runtime on startup; if it is missing, no .NET runtime is connected and any legacy DotNet.invokeMethod / invokeMethodAsync call has nowhere to route.

Solutions

  1. Wait for Blazor to be ready before calling: await Blazor.start(); or run code after the blazor:afterstarted event.
  2. If using the library standalone, call DotNet.attachDispatcher(yourDispatcher) first.
  3. Check the browser console for Blazor startup errors that prevented attachDispatcher.

Example fix

// before
DotNet.invokeMethodAsync('MyLib', 'DoThing'); // runs in <head>, Blazor not started

// after
document.addEventListener('blazor:afterstarted', () => {
    DotNet.invokeMethodAsync('MyLib', 'DoThing');
});
Defensive patterns

Strategy: validation

Validate before calling

function isBlazorReady() { return typeof Blazor !== 'undefined' && Blazor._internal && defaultCallDispatcherSet; }
// or simpler: wait for the event
document.addEventListener('blazor:afterstarted', () => { /* safe to call DotNet.invokeMethodAsync */ });

Try / catch

try { return await DotNet.invokeMethodAsync('MyLib', 'Method'); } catch (e) { if (/No call dispatcher has been set/.test(e.message)) { console.warn('Blazor not started yet; retry after blazor:afterstarted.'); } throw e; }

Prevention

When it happens

Trigger: Calling DotNet.invokeMethod or DotNet.invokeMethodAsync before Blazor has finished initializing (before Blazor.start() or before the auto-start script ran). Also when using the JS interop library standalone without attaching a dispatcher.

Common situations: A script in <head> or early <body> calling DotNet.invokeMethodAsync before Blazor is ready; using Microsoft.JSInterop.js outside of Blazor without a custom dispatcher; Blazor startup failed silently so attachDispatcher never ran.

Related errors


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

Appendix: source

Thrown at src/JSInterop/Microsoft.JSInterop.JS/src/src/Microsoft.JSInterop.ts:255

  function parseJsonWithRevivers(callDispatcher: CallDispatcher, json: string | null): any {
      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,

View on GitHub (pinned to 3600ca084e)