dotnet/aspnetcore · error
JS object instance with ID ${targetInstanceId} does not exis
Error message
JS object instance with ID ${targetInstanceId} does not exist (has it been disposed?). What it means
Thrown by findJSFunction when cachedJSObjectsById[targetInstanceId] is undefined. Every JS object reference handed to .NET is cached by id; disposeJSObjectReferenceById (called when .NET disposes the JSObjectReference or a DotNetObject is GC'd) deletes that entry. A later call addressed to that id therefore cannot resolve the target.
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 294cab2f9b)
Solutions
- Null-out and stop using the reference after disposal; set jsRef = null in the .NET dispose path.
- Capture a fresh reference each time the element/component mounts rather than reusing a stale one.
- Pin DotNetObject instances with DotNetObjectReference.Create and dispose explicitly; keep the .NET side alive for the call's lifetime.
- Guard the call: check the ref is valid before invoking.
Example fix
// before
@inject IJSRuntime JS
@code {
private JSObjectReference _module;
protected override async Task OnAfterRenderAsync(bool first) {
if (first) _module = await JS.InvokeAsync<JSObjectReference>("import","./lib.js");
}
public void Dispose() { /* forgot to dispose _module */ }
async Task Late() => await _module.InvokeVoidAsync("fn"); // stale id
}
// after
public async ValueTask DisposeAsync() {
if (_module is not null) { await _module.DisposeAsync(); _module = null; }
} Defensive patterns
Strategy: validation
Validate before calling
// .NET: track validity
private JSObjectReference _ref;
private bool _disposed;
async Task CallAsync() {
if (_disposed || _ref is null) throw new ObjectDisposedException(nameof(_ref));
await _ref.InvokeVoidAsync("fn");
} Type guard
null
Try / catch
try {
await jsRef.invokeMethodAsync('fn');
} catch (e) {
if (/has it been disposed\?/i.test(e.message)) { jsRef = null; /* reacquire */ }
else throw e;
} Prevention
- Implement IAsyncDisposable and dispose JSObjectReference/DotNetObjectReference.
- Set references to null after disposal.
- Do not capture ElementReference across re-renders that may unmount the element.
When it happens
Trigger: .NET holds a JSObjectReference or ElementReference whose id was already disposed; calling jsRef.invokeMethod after the ref was disposed; an element reference that survived a re-render where the element was removed; calling on a DotNetObject after dispose.
Common situations: Holding a JSObjectReference in a long-lived service after IJSRuntime.Dispose or component disposal; using ElementReference across a re-render where the element unmounted; memory-pressure-driven GC of a DotNetObject that was not pinned.
Related errors
- JS object instance with Id '${id}' does not exist. It may ha
- Interop methods are already registered for renderer ${render
- Interop methods are not registered for renderer ${rendererId
- No interop methods are registered for renderer ${rendererId}
- Renderer with ID '${rendererId}' is not listening for naviga
AI-assisted analysis of dotnet/aspnetcore@294cab2f9b (2026-08-06).
Data as JSON: /api/errors/32b668194fbb158a.
Report an issue: GitHub.