{"record":{"id":"bb673ad721439873","repo":"linera-io/linera-protocol","slug":"no-metamask-accounts-connected","errorCode":null,"errorMessage":"No MetaMask accounts connected","messagePattern":"No MetaMask accounts connected","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"web/@linera/metamask/src/signer.ts","lineNumber":50,"sourceCode":"  constructor() {\n    if (typeof window === \"undefined\" || !window.ethereum) {\n      throw new Error(\"MetaMask is not available\");\n    }\n    this.provider = new ethers.BrowserProvider(window.ethereum!);\n  }\n\n  async sign(owner: string, value: Uint8Array): Promise<string> {\n    if (!window.ethereum) {\n      throw new Error(\"MetaMask is not available\");\n    }\n\n    // Explicitly type the result and check for undefined\n    const accounts = (await window.ethereum.request({\n      method: \"eth_requestAccounts\",\n    })) as string[] | undefined;\n\n    if (!accounts || accounts.length === 0) {\n      throw new Error(\"No MetaMask accounts connected\");\n    }\n\n    const connected = accounts.find(\n      (acc) => acc.toLowerCase() === owner.toLowerCase(),\n    );\n    if (!connected) {\n      throw new Error(\n        `MetaMask is not connected with the requested owner: ${owner}`,\n      );\n    }\n\n    // Encode message as hex string\n    const msgHex = `0x${uint8ArrayToHex(value)}`;\n    try {\n      const signature = (await window.ethereum.request({\n        method: \"personal_sign\",\n        params: [msgHex, owner],\n      })) as string;","sourceCodeStart":32,"sourceCodeEnd":68,"githubUrl":"https://github.com/linera-io/linera-protocol/blob/6c226ddcb332ef55118dc8d0aafbd093d5420899/web/@linera/metamask/src/signer.ts#L32-L68","documentation":"share_ownership adds a new owner to the chain, which requires the chain to currently have active ownership to build a valid Ownership operation. The guard ensure!(ownership.is_active()) fails with ChainError::InactiveChain when the chain has no owners at all — there is nobody left to sign the ownership change, so the operation cannot proceed.","triggerScenarios":"Calling share_ownership on a chain where manager.ownership is inactive (no regular and no super owners). Producers: chains created but never assigned an owner; chains where all owner weights were set to 0; using a client bound to the wrong chain id.","commonSituations":"Misconfigured CHAIN_ID / wallet pointing at an ownerless chain; child chains not yet assigned from the parent; automated setups that try to rotate keys on a chain that lost its owners.","solutions":["Verify you are operating on the right chain: print chain_info() and check manager.ownership before calling share_ownership.","For an ownerless child chain, complete the assignment from the parent (assign_new_chain_to_key) so it becomes active, then share ownership.","If all owners were removed by mistake, the chain can only be recovered through governance/admin procedures — file/consult the Linera team; do not retry share_ownership.","In application code, gate ownership operations on an is_active() pre-check and surface a clear message."],"exampleFix":"// before: sharing ownership on an ownerless chain\nclient.share_ownership(new_owner, 100).await?; // InactiveChain\n\n// after: check ownership first and assign from the parent if inactive\nlet ownership = client.chain_info().await?.manager.ownership;\nif !ownership.is_active() {\n    parent.assign_new_chain_to_key(owner, description).await?;\n}\nclient.share_ownership(new_owner, 100).await?;","handlingStrategy":"validation","validationCode":"// Guard ownership mutations with an activity check\nlet ownership = client.prepare_chain().await?.manager.ownership.clone();\nif !ownership.is_active() {\n    return Err(anyhow::anyhow!(\"cannot share ownership: chain {} is inactive\", client.chain_id()));\n}","typeGuard":"pub async fn chain_is_active_for_ownership(client: &ChainClient) -> Result<bool, Error> {\n    Ok(client.chain_info().await?.manager.ownership.is_active())\n}","tryCatchPattern":"match client.share_ownership(new_owner, weight).await {\n    Ok(outcome) => outcome,\n    Err(Error::ChainError(ChainError::InactiveChain(chain_id))) => {\n        // wrong chain or ownerless chain: assign an owner from the parent, or stop\n        return Err(anyhow::anyhow!(\"chain {chain_id} has no owners; complete owner assignment first\"));\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Double-check the chain id in wallet/config before ownership operations.","Complete assign_new_chain_to_key for new child chains before rotating or sharing ownership.","Surface ownership state in ops dashboards so ownerless chains are visible.","Treat ownerless-but-funded chains as requiring governance recovery; do not script retries."],"tags":["linera","chain-ownership","inactive-chain","key-rotation"],"backgroundTag":"chain-inactive","analyzedSha":"6c226ddcb332ef55118dc8d0aafbd093d5420899","analyzedAt":"2026-08-22T22:49:09.787Z","schemaVersion":2},"datasetVersion":"2026-08-23T01:17:44.959Z"}