dotnet/aspnetcore · error · Error

JS object instance with ID

Error message

JS object instance with ID ${targetInstanceId} does not exist (has it been disposed?).

What it means

Thrown by DotNet.findJSFunction() when no cached JSObject exists for the given targetInstanceId. Every JS interop call from .NET targets an instance by numeric ID (0 = window); if that ID was disposed or never registered, the call cannot resolve. The most common cause is using a JS object reference after it was disposed.

Solutions

  1. Do not use an IJSObjectReference after calling Dispose on it.
  2. After Blazor reconnect, re-acquire JS object references rather than reusing old ones.
  3. Track disposal state on the .NET side and skip calls to disposed references.

Example fix

// C# before
await jsRef.InvokeVoidAsync("doThing");
await jsRef.DisposeAsync();
await jsRef.InvokeVoidAsync("doThing"); // throws in JS

// after
await jsRef.InvokeVoidAsync("doThing");
await jsRef.DisposeAsync();
jsRef = null; // null and re-acquire if needed
Defensive patterns

Strategy: validation

Validate before calling

// .NET: null-check and dispose-track IJSObjectReference before invoking.
if (jsRef is null) { return; }
await jsRef.InvokeVoidAsync("doThing");

Try / catch

try { await jsRef.InvokeVoidAsync("doThing"); } catch (JSException e) when (e.Message.Contains("does not exist")) { jsRef = null; /* re-acquire or give up */ }

Prevention

When it happens

Trigger: .NET calls a JS function on an IJSObjectReference that was already disposed (or whose underlying object was garbage-collected via disposeJSObjectReferenceById). Also when the ID is stale after a Blazor circuit reconnect or page refresh.

Common situations: Calling a method on a disposed IJSObjectReference; holding a JS object reference across a Blazor Server reconnect that lost the cache; calling dispose on a reference then using it again.

Related errors


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

Appendix: source

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

      }
  }

  function formatError(error: Error | string): string {
      if (error instanceof Error) {
          return `${error.message}\n${error.stack}`;
      }

      return error ? error.toString() : "null";
  }

  export function findJSFunction(identifier: string, targetInstanceId: number, callType?: JSCallType): Function {
      const targetInstance = cachedJSObjectsById[targetInstanceId];

      if (targetInstance) {
          return targetInstance.resolveInvocationHandler(identifier, callType ?? JSCallType.FunctionCall);
      }

      throw new Error(`JS object instance with ID ${targetInstanceId} does not exist (has it been disposed?).`);
  }

  export function disposeJSObjectReferenceById(id: number) {
      delete cachedJSObjectsById[id];
  }

  /**
   * Traverses the object hierarchy to find an object member specified by the identifier.
   *
   * @param obj Root object to search in.
   * @param identifier Complete identifier of the member to find, e.g. "document.location.href".
   * @returns A tuple containing the immediate parent of the member and the member name.
   */
  export function findObjectMember(obj: any, identifier: string): [any, string] {
      const keys = identifier.split(".");
      let current = obj;

      // First, we iterate over all but the last key. We throw error for missing intermediate keys.

View on GitHub (pinned to 3600ca084e)