dotnet/aspnetcore · error · Error
JS object instance with Id
Error message
JS object instance with Id '${id}' does not exist. It may have been disposed. What it means
Thrown by the built-in reviveReference JSON reviver when deserializing a payload that carries a __jsObjectId marker whose ID is not in cachedJSObjectsById. This fires during JSON.parse of arguments coming from .NET; the .NET side referenced a JS object that the JS runtime no longer holds (disposed or never existed on this client). Distinct from error 91 (which fires at call dispatch time); this fires during argument deserialization.
Solutions
- Do not send disposed JS object references back from .NET; track disposal on the .NET side.
- After a reconnect, re-establish JS references rather than reusing stale IDs.
- Avoid persisting/serializing IJSObjectReference IDs across sessions.
Example fix
// C# before
var jsRef = await JS.InvokeAsync<IJSObjectReference>("getRef");
await jsRef.DisposeAsync();
await JS.InvokeVoidAsync("useRef", jsRef); // sends disposed id -> reviver throws
// after
await jsRef.DisposeAsync();
jsRef = null;
// re-acquire before passing back Defensive patterns
Strategy: validation
Validate before calling
// .NET: do not pass disposed IJSObjectReference back to JS.
if (jsRef is null || _disposed) { return; }
await JS.InvokeVoidAsync("useRef", jsRef); Try / catch
try { /* call that round-trips a jsRef */ } catch (JSException e) when (e.Message.Contains("does not exist. It may have been disposed")) { jsRef = null; /* re-acquire or stop using */ } Prevention
- Null out IJSObjectReference fields after DisposeAsync.
- Never reuse JS object references across Blazor circuit reconnects.
- Do not serialize or persist JS object IDs across sessions.
When it happens
Trigger: .NET sends back a JS object reference (e.g. round-tripping an IJSObjectReference) that was disposed on the JS side, or whose ID belongs to a different Blazor circuit/session. The reviver cannot resolve the marker to a wrapped object.
Common situations: Round-tripping a disposed IJSObjectReference; Blazor Server circuit reconnect where the JS-side object cache was reset but .NET still holds old IDs; cross-frame/cross-window references.
Related errors
- Byte array index ' ' does not exist.
- Cannot create a JSObjectReference from the value
- Cannot create a JSStreamReference from the value
- JS object instance with ID
- Cannot create a JSStreamReference from the value
AI-assisted analysis of dotnet/aspnetcore@3600ca084e (2026-08-11).
Data as JSON: /api/errors/84e2e8cceda2f63f.
Report an issue: GitHub.
Appendix: source
Thrown at src/JSInterop/Microsoft.JSInterop.JS/src/src/Microsoft.JSInterop.ts:739
public serializeAsArg() {
return { [dotNetObjectRefKey]: this._id };
}
}
attachReviver(function reviveReference(key: any, value: any) {
if (value && typeof value === "object") {
if (value.hasOwnProperty(dotNetObjectRefKey)) {
return new DotNetObject(value[dotNetObjectRefKey], currentCallDispatcher!);
} else if (value.hasOwnProperty(jsObjectIdKey)) {
const id = value[jsObjectIdKey];
const jsObject = cachedJSObjectsById[id];
if (jsObject) {
return jsObject.getWrappedObject();
}
throw new Error(`JS object instance with Id '${id}' does not exist. It may have been disposed.`);
} else if (value.hasOwnProperty(byteArrayRefKey)) {
const index = value[byteArrayRefKey];
const byteArray = currentCallDispatcher!.processByteArray(index);
if (byteArray === undefined) {
throw new Error(`Byte array index '${index}' does not exist.`);
}
return byteArray;
} else if (value.hasOwnProperty(dotNetStreamRefKey)) {
const streamId = value[dotNetStreamRefKey];
const streamPromise = currentCallDispatcher!.getDotNetStreamPromise(streamId);
return new DotNetStream(streamPromise);
}
}
// Unrecognized - let another reviver handle it
return value;
});
View on GitHub (pinned to 3600ca084e)