{"record":{"id":"f330f11f21dbaba3","repo":"linera-io/linera-protocol","slug":"client-disposed-while-being-referenced-elsewhere","errorCode":null,"errorMessage":"Client disposed while being referenced elsewhere","messagePattern":"Client disposed while being referenced elsewhere","errorType":"exception","errorClass":"JsError","httpStatus":null,"severity":"error","filePath":"web/@linera/client/src/client.rs","lineNumber":161,"sourceCode":"        })\n    }\n\n    /// Cleanly shut down the client, completing when it is destroyed and all\n    /// resources it owns are released.\n    ///\n    /// # Errors\n    ///\n    /// If the context is being referenced by any other objects (chains,\n    /// applications…). Free these with `.free()` before disposing of this\n    /// object.\n    ///\n    /// Propagates any errors that occurred during background execution of the\n    /// client.\n    #[wasm_bindgen(js_name = asyncDispose)]\n    pub async fn async_dispose(self) -> Result<()> {\n        self.stop().await?;\n\n        let context = Arc::into_inner(self.context).ok_or(Error::new(\n            \"Client disposed while being referenced elsewhere\",\n        ))?;\n\n        drop(context);\n\n        Ok(())\n    }\n}\n","sourceCodeStart":143,"sourceCodeEnd":170,"githubUrl":"https://github.com/linera-io/linera-protocol/blob/6c226ddcb332ef55118dc8d0aafbd093d5420899/web/@linera/client/src/client.rs#L143-L170","documentation":"`Client.asyncDispose()` (exposed to JS as `asyncDispose`) shuts down the web client: it stops the chain listener, then consumes the internal `Arc<ClientContext>` with `Arc::into_inner`. That only succeeds when this instance holds the last reference; every `Chain` object created via `client.chain(chainId)` clones the context, so any live `Chain` (or Client clone) keeps a reference alive and `Arc::into_inner` returns `None`, producing this error.","triggerScenarios":"Calling `await client.asyncDispose()` while one or more `Chain` handles from `client.chain(...)` are still alive; keeping another clone of the Client somewhere; a long-lived promise still holding a Chain during teardown.","commonSituations":"Web dApp teardown paths disposing the client before per-chain handles; UI components unmounting in the wrong order; error paths that skip cleanup of chain handles.","solutions":["Call `.free()` on every Chain (and any other handle) obtained from the client before calling `asyncDispose()`.","Centralize teardown: free all tracked chains in one place, then dispose the client.","Keep an array of created chains and free them in a loop right before disposal.","If the error persists, hunt for forgotten Client clones or unresolved promises holding a Chain."],"exampleFix":"// before\nconst chain = client.chain(chainId);\nawait client.asyncDispose(); // 'Client disposed while being referenced elsewhere'\n\n// after\nconst chains = [client.chain(chainId)];\n// ... use chains ...\nfor (const c of chains) c.free();\nawait client.asyncDispose();","handlingStrategy":"validation","validationCode":"const openChains = new Set();\nfunction acquireChain(id) { const c = client.chain(id); openChains.add(c); return c; }\nasync function disposeClient() { for (const c of openChains) c.free(); openChains.clear(); await client.asyncDispose(); }","typeGuard":"function allChainsFreed(tracked: Set<Chain>): boolean { return tracked.size === 0; }","tryCatchPattern":"try { await client.asyncDispose(); } catch (e) { if (/disposed while being referenced/i.test(e.message)) { freeAllChains(); await client.asyncDispose(); } else throw e; }","preventionTips":["Track every Chain handle created from client.chain() and free() it in teardown.","Dispose the client only from a single top-level teardown routine.","Avoid cloning the Client into long-lived structures.","On error paths, free chains before rethrowing."],"tags":["web-client","wasm","lifecycle","dispose","resource-management"],"backgroundTag":"resource-still-referenced","analyzedSha":"6c226ddcb332ef55118dc8d0aafbd093d5420899","analyzedAt":"2026-08-22T22:49:09.787Z","schemaVersion":2},"datasetVersion":"2026-08-23T01:17:44.959Z"}