linera-io/linera-protocol · error · JsError

chain {chain_id} doesn't exist in wallet

Error message

chain {chain_id} doesn't exist in wallet

What it means

The web wallet keeps its chains in an in-memory `wallet::Memory`; `setOwner(chainId, owner)` looks the chain up with `Memory::mutate`, which returns `None` when the ChainId is unknown, and that `None` is turned into this error. It means this Wallet instance never learned about the chain — it was not created, imported, or assigned in this wallet.

Source

Thrown at web/@linera/client/src/wallet.rs:50

            lock: None,
        }
    }
}

#[wasm_bindgen]
impl Wallet {
    /// Set the owner of a chain (the account used to sign blocks on this chain).
    ///
    /// # Errors
    ///
    /// If the provided `ChainId` or `AccountOwner` are in the wrong format.
    #[wasm_bindgen(js_name = setOwner)]
    pub async fn set_owner(&self, chain_id: JsValue, owner: JsValue) -> Result<()> {
        let chain_id = serde_wasm_bindgen::from_value(chain_id)?;
        let owner = serde_wasm_bindgen::from_value(owner)?;
        self.chains
            .mutate(chain_id, |chain| chain.owner = Some(owner))
            .ok_or(Error::new(&format!(
                "chain {chain_id} doesn't exist in wallet"
            )))
    }

    #[must_use]
    /// Get the name of the wallet. Wallets with different names should use different
    /// storage; only one wallet can use the same name at a time.
    pub fn name(&self) -> String {
        self.default
            .map_or_else(|| "default".into(), |name| name.to_string())
    }

    /// Lock the wallet, preventing anyone else from using a wallet with this name.
    ///
    /// If the wallet is already locked, this is a no-op.
    ///
    /// # Errors
    /// If the wallet is locked elsewhere.

View on GitHub (pinned to 6c226ddcb3)

Solutions

  1. Confirm the chain exists in this wallet (check its chain list) and create/import it if missing.
  2. Use the exact ChainId value returned when the chain was created or exposed as the wallet's default chain.
  3. After creating a chain, wait for the wallet update to land before calling setOwner.
  4. Verify the wallet was constructed with the matching genesis config for that chain.

Example fix

// before
await wallet.setOwner(someChainIdFromString, owner); // "chain e5-… doesn't exist in wallet"

// after
const known = await wallet.chains(); // or wallet default chain
if (!known.some(c => c.equals(target))) await importOrCreateChain(target);
await wallet.setOwner(target, owner);
Defensive patterns

Strategy: validation

Validate before calling

const known = new Set((await wallet.chains()).map(String));
if (!known.has(String(chainId))) throw new Error(`chain ${chainId} not in wallet; create or import it first`);

Type guard

async function walletHasChain(wallet: Wallet, chainId: ChainId): Promise<boolean> { return (await wallet.chains()).some(c => c.equals(chainId)); }

Try / catch

try { await wallet.setOwner(chainId, owner); } catch (e) { if (/doesn't exist in wallet/i.test(e.message)) { await importOrCreate(chainId); await wallet.setOwner(chainId, owner); } else throw e; }

Prevention

When it happens

Trigger: Calling `wallet.setOwner(chainId, owner)` with a ChainId that is not among the wallet's chains (typo, wrong network, chain created in a different wallet); calling it before the wallet was updated after chain creation.

Common situations: dApps constructing chain IDs from strings or from another user's account; mixing chain IDs from a different genesis/testnet; race where setOwner runs before the creation result is applied to the wallet.

Related errors


AI-assisted analysis of linera-io/linera-protocol@6c226ddcb3 (2026-08-22). Data as JSON: /api/errors/485b6c2a54cde507. Report an issue: GitHub.