{"record":{"id":"84e2e8cceda2f63f","repo":"dotnet/aspnetcore","slug":"js-object-instance-with-id-id-does-not-exist","errorCode":null,"errorMessage":"JS object instance with Id '${id}' does not exist. It may have been disposed.","messagePattern":"JS object instance with Id '(.+?)' does not exist\\. It may have been disposed\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/JSInterop/Microsoft.JSInterop.JS/src/src/Microsoft.JSInterop.ts","lineNumber":739,"sourceCode":"\n      public serializeAsArg() {\n          return { [dotNetObjectRefKey]: this._id };\n      }\n  }\n\n  attachReviver(function reviveReference(key: any, value: any) {\n      if (value && typeof value === \"object\") {\n          if (value.hasOwnProperty(dotNetObjectRefKey)) {\n              return new DotNetObject(value[dotNetObjectRefKey], currentCallDispatcher!);\n          } else if (value.hasOwnProperty(jsObjectIdKey)) {\n              const id = value[jsObjectIdKey];\n              const jsObject = cachedJSObjectsById[id];\n\n              if (jsObject) {\n                  return jsObject.getWrappedObject();\n              }\n\n              throw new Error(`JS object instance with Id '${id}' does not exist. It may have been disposed.`);\n          } else if (value.hasOwnProperty(byteArrayRefKey)) {\n              const index = value[byteArrayRefKey];\n              const byteArray = currentCallDispatcher!.processByteArray(index);\n              if (byteArray === undefined) {\n                  throw new Error(`Byte array index '${index}' does not exist.`);\n              }\n              return byteArray;\n          } else if (value.hasOwnProperty(dotNetStreamRefKey)) {\n              const streamId = value[dotNetStreamRefKey];\n              const streamPromise = currentCallDispatcher!.getDotNetStreamPromise(streamId);\n              return new DotNetStream(streamPromise);\n          }\n      }\n\n      // Unrecognized - let another reviver handle it\n      return value;\n  });\n","sourceCodeStart":721,"sourceCodeEnd":757,"githubUrl":"https://github.com/dotnet/aspnetcore/blob/294cab2f9b2e03af6b953820c7ab497c3c8b7ad9/src/JSInterop/Microsoft.JSInterop.JS/src/src/Microsoft.JSInterop.ts#L721-L757","documentation":"Thrown inside the JSON reviveReference reviver when a payload carries a {jsObjectId: N} marker but cachedJSObjectsById[N] is undefined. Unlike 83 (which is thrown on the invoke path for findJSFunction), this fires during deserialization of a value being passed into JS — a JS object reference being sent back across the boundary that no longer exists in the cache.","triggerScenarios":".NET passes back to JS a previously-captured {__jsObjectId:N} whose object was disposed via disposeJSObjectReferenceById; deserializing an old message in a test harness without the cache populated; crossing a circuit/worker boundary where the cache is per-dispatcher.","commonSituations":"Round-tripping a JSObjectReference JSON blob after it was disposed; serializing a stale ref captured before a reconnect; replaying a captured interop payload in tests against a fresh runtime; a long-lived .NET object that held onto a serialized jsObjectId across a circuit restart.","solutions":["Do not persist the serialized form of a JSObjectReference across call boundaries or sessions.","Dispose references symmetrically and stop serializing them after disposal.","In tests, seed cachedJSObjectsById or avoid replaying raw payloads.","On circuit reconnect, re-acquire references instead of reusing stale ids."],"exampleFix":"// before\n// .NET caches string json = JsonSerializer.Serialize(jsObjRef) and reuses after dispose\n\n// after\n// re-acquire the JS object via interop after reconnect\nvar fresh = await JS.InvokeAsync<IJSObjectReference>(\"getHandle\");","handlingStrategy":"validation","validationCode":"// do not persist serialized JSObjectReference across calls\n// reacquire on the live dispatcher each time\nvar fresh = await JS.InvokeAsync<IJSObjectReference>(\"getHandle\");","typeGuard":"null","tryCatchPattern":"try { JSON.parse(json, reviver); } catch (e) { if (/does not exist\\. It may have been disposed/i.test(e.message)) { /* reacquire ref */ } else throw e; }","preventionTips":["Never cache the serialized form of a JSObjectReference.","Re-acquire references after circuit/worker reconnect.","Dispose references symmetrically with .NET."],"tags":["blazor","jsinterop","serialization","reviver","disposal","lifecycle"],"analyzedSha":"294cab2f9b2e03af6b953820c7ab497c3c8b7ad9","analyzedAt":"2026-08-06T20:08:02.189Z","schemaVersion":2},"datasetVersion":"2026-08-06T23:17:07.152Z"}