{"record":{"id":"83da029c2d66ed0f","repo":"dotnet/aspnetcore","slug":"the-circuit-associated-with-this-dispatcher-is-no","errorCode":null,"errorMessage":"The circuit associated with this dispatcher is no longer available.","messagePattern":"The circuit associated with this dispatcher is no longer available\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/Components/Web.JS/src/Platform/Circuits/CircuitManager.ts","lineNumber":528,"sourceCode":"\n  // Implements DotNet.DotNetCallDispatcher\n  public endInvokeJSFromDotNet(asyncHandle: number, succeeded: boolean, argsJson: any): void {\n    this.throwIfDispatchingWhenDisposed();\n    if (asyncHandle !== 0) {\n      this.changeActivity(-1);\n    }\n    this._connection!.send('EndInvokeJSFromDotNet', asyncHandle, succeeded, argsJson);\n  }\n\n  // Implements DotNet.DotNetCallDispatcher\n  public sendByteArray(id: number, data: Uint8Array): void {\n    this.throwIfDispatchingWhenDisposed();\n    this._connection!.send('ReceiveByteArray', id, data);\n  }\n\n  private throwIfDispatchingWhenDisposed() {\n    if (this._disposed) {\n      throw new Error('The circuit associated with this dispatcher is no longer available.');\n    }\n  }\n\n  public sendLocationChanged(uri: string, state: string | undefined, intercepted: boolean): Promise<void> {\n    return this._connection!.send('OnLocationChanged', uri, state, intercepted);\n  }\n\n  public sendLocationChanging(callId: number, uri: string, state: string | undefined, intercepted: boolean): Promise<void> {\n    return this._connection!.send('OnLocationChanging', callId, uri, state, intercepted);\n  }\n\n  public sendJsDataStream(data: ArrayBufferView | Blob, streamId: number, chunkSize: number) {\n    this.changeActivity(1);\n    return sendJSDataStream(this._connection!, data, streamId, chunkSize, () => this.changeActivity(-1));\n  }\n\n  public resolveElement(sequenceOrIdentifier: string): LogicalElement {\n    // It may be a root component added by JS","sourceCodeStart":510,"sourceCodeEnd":546,"githubUrl":"https://github.com/dotnet/aspnetcore/blob/294cab2f9b2e03af6b953820c7ab497c3c8b7ad9/src/Components/Web.JS/src/Platform/Circuits/CircuitManager.ts#L510-L546","documentation":"Thrown by throwIfDispatchingWhenDisposed() — invoked from beginInvokeDotNetFromJS, endInvokeJSFromDotNet, and sendByteArray — when _disposed is true. Once a circuit is disposed, the underlying SignalR connection is gone, so any JS->.NET interop dispatch is rejected because there is no server endpoint to receive it.","triggerScenarios":"Firing a JS interop call (invokeMethodAsync from JS, or a pending DotNet callback) after the circuit was disposed — e.g. user navigated away, tab closed, circuit dropped, or dispose() ran while async interop was still queued.","commonSituations":"Long-running JS tasks completing after navigation/circuit loss; event handlers firing during teardown; cleanup callbacks invoking .NET methods on a disposed circuit.","solutions":["Cancel/short-circuit JS work before disposing the circuit.","Guard interop calls with a disposed flag in your JS interop wrappers.","On the .NET side, catch OperationCanceledException / JSDisconnectedException from interop and treat as expected during teardown."],"exampleFix":"// before\nawait dotNetRef.invokeMethodAsync('OnDone'); // throws if circuit disposed\n\n// after\nif (!disposed) {\n  try { await dotNetRef.invokeMethodAsync('OnDone'); }\n  catch { /* circuit gone, ignore */ }\n}","handlingStrategy":"try-catch","validationCode":"// Track disposal in JS and short-circuit interop.\nlet disposed = false;\ncircuitManager.dispose(); disposed = true;\nif (!disposed) { await dotNetRef.invokeMethodAsync('DoWork'); }","typeGuard":null,"tryCatchPattern":"try { await dotNetRef.invokeMethodAsync('OnDone'); }\ncatch (e) {\n  // circuit gone during async work — expected during teardown\n  if (/no longer available|disposed/i.test(e.message)) return;\n  throw e;\n}","preventionTips":["Cancel pending JS work before disposing the circuit.","Catch and swallow interop errors that occur during teardown.","Maintain a disposed flag and check before every interop call."],"tags":["blazor-server","interop","lifecycle","disposed"],"analyzedSha":"294cab2f9b2e03af6b953820c7ab497c3c8b7ad9","analyzedAt":"2026-08-06T20:08:02.189Z","schemaVersion":2},"datasetVersion":"2026-08-06T23:17:07.152Z"}