{"record":{"id":"95b5dd19bb3584c7","repo":"dotnet/aspnetcore","slug":"the-current-dispatcher-does-not-support-synchronou","errorCode":null,"errorMessage":"The current dispatcher does not support synchronous calls from JS to .NET. Use invokeDotNetMethodAsync instead.","messagePattern":"The current dispatcher does not support synchronous calls from JS to \\.NET\\. Use invokeDotNetMethodAsync instead\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/JSInterop/Microsoft.JSInterop.JS/src/src/Microsoft.JSInterop.ts","lineNumber":477,"sourceCode":"          this.completePendingCall(parseInt(asyncCallId, 10), success, resultOrError);\n      }\n\n      invokeDotNetStaticMethod<T>(assemblyName: string, methodIdentifier: string, ...args: any[]): T | null {\n          return this.invokeDotNetMethod<T>(assemblyName, methodIdentifier, null, args);\n      }\n\n      invokeDotNetStaticMethodAsync<T>(assemblyName: string, methodIdentifier: string, ...args: any[]): Promise<T> {\n          return this.invokeDotNetMethodAsync<T>(assemblyName, methodIdentifier, null, args);\n      }\n\n      invokeDotNetMethod<T>(assemblyName: string | null, methodIdentifier: string, dotNetObjectId: number | null, args: any[] | null): T | null {\n          if (this._dotNetCallDispatcher.invokeDotNetFromJS) {\n              const argsJson = stringifyArgs(this, args);\n              const resultJson = this._dotNetCallDispatcher.invokeDotNetFromJS(assemblyName, methodIdentifier, dotNetObjectId, argsJson);\n              return resultJson ? parseJsonWithRevivers(this, resultJson) : null;\n          }\n\n          throw new Error(\"The current dispatcher does not support synchronous calls from JS to .NET. Use invokeDotNetMethodAsync instead.\");\n      }\n\n      invokeDotNetMethodAsync<T>(assemblyName: string | null, methodIdentifier: string, dotNetObjectId: number | null, args: any[] | null): Promise<T> {\n          if (assemblyName && dotNetObjectId) {\n              throw new Error(`For instance method calls, assemblyName should be null. Received '${assemblyName}'.`);\n          }\n\n          const asyncCallId = this._nextAsyncCallId++;\n          const resultPromise = new Promise<T>((resolve, reject) => {\n              this._pendingAsyncCalls[asyncCallId] = { resolve, reject };\n          });\n\n          try {\n              const argsJson = stringifyArgs(this, args);\n              this._dotNetCallDispatcher.beginInvokeDotNetFromJS(asyncCallId, assemblyName, methodIdentifier, dotNetObjectId, argsJson);\n          } catch (ex) {\n              // Synchronous failure\n              this.completePendingCall(asyncCallId, false, ex);","sourceCodeStart":459,"sourceCodeEnd":495,"githubUrl":"https://github.com/dotnet/aspnetcore/blob/294cab2f9b2e03af6b953820c7ab497c3c8b7ad9/src/JSInterop/Microsoft.JSInterop.JS/src/src/Microsoft.JSInterop.ts#L459-L495","documentation":"Thrown by DotNet.invokeDotNetMethod when the active call dispatcher has no synchronous invokeDotNetFromJS implementation. This is a capability mismatch: Blazor WebAssembly registers a synchronous dispatcher (the .NET runtime is in-process), but Blazor Server and other remoting-based hosts only expose beginInvokeDotNetFromJS because the call must cross a network boundary asynchronously. The message explicitly redirects you to the async path.","triggerScenarios":"Calling DotNet.invokeMethod / invokeMethodAsync-synchronously on a host that does not set _dotNetCallDispatcher.invokeDotNetFromJS. Concretely: a JS module calls DotNet.invokeMethod('MyAssembly','MyMethod') under Blazor Server, or a JS component calls dotNetRef.invokeMethod(...) (DotNetObject.invokeMethod at Microsoft.JSInterop.ts:710) on Blazor Server.","commonSituations":"Running the same JS interop code against Blazor Server that worked on Blazor WebAssembly; library code that assumed an in-process .NET runtime; misreading the docs and using the sync overload everywhere.","solutions":["Switch the JS call to the async variant: DotNet.invokeMethodAsync('MyAssembly','MyMethod') or dotNetRef.invokeMethodAsync('Method').","If you control the call site, make the surrounding function async and await the result.","Avoid DotNetObject.invokeMethod / DotNet.invokeMethod entirely in code that must run on Blazor Server; keep only the async overloads.","If you truly need sync semantics, run that code only on Blazor WebAssembly and gate the host via feature detection."],"exampleFix":"// before\nconst result = DotNet.invokeMethod('MyAssembly', 'Calculate', input);\n\n// after\nconst result = await DotNet.invokeMethodAsync('MyAssembly', 'Calculate', input);","handlingStrategy":"fallback","validationCode":"function canSyncInvokeDotNet() {\n  // dispatcher is internal; approximate by host detection\n  return typeof Blazor !== 'undefined' && /WebAssembly/.test(navigator.userAgent) && location.protocol.startsWith('http');\n}","typeGuard":"type DotNetSyncCapable = { invokeMethod(...args:any[]): any };\nfunction supportsSyncDotNet(d: any): d is DotNetSyncCapable {\n  return typeof d?.invokeMethod === 'function' && !String(d.invokeMethod).includes('throw');\n}","tryCatchPattern":"try {\n  DotNet.invokeMethod('Asm','M');\n} catch (e) {\n  if (/Use invokeDotNetMethodAsync/.test(e.message)) {\n    return await DotNet.invokeMethodAsync('Asm','M');\n  }\n  throw e;\n}","preventionTips":["Default to async overloads in all cross-host JS interop.","Feature-detect the host before relying on sync semantics.","Document each JS interop call as Server-safe or WASM-only."],"tags":["blazor","jsinterop","async","webassembly","server"],"analyzedSha":"294cab2f9b2e03af6b953820c7ab497c3c8b7ad9","analyzedAt":"2026-08-06T20:08:02.189Z","schemaVersion":2},"datasetVersion":"2026-08-06T23:17:07.152Z"}