linera-io/linera-protocol · error

nonexistent chain `{chain_id}`

Error message

nonexistent chain `{chain_id}`

What it means

WalletState::forget_keys calls mutate(chain_id, ...), which returns None when the chain_id key is absent from the wallet's chain map. The outer ok_or_else converts that None into this anyhow error, meaning the wallet file has no entry for the given ChainId at all.

Source

Thrown at linera-wallet-json/src/wallet.rs:199

    }

    /// Applies a mutation to the chain with the given ID, saving afterwards. Returns `None`
    /// if the chain is not in the wallet.
    pub fn mutate<R>(
        &self,
        chain_id: ChainId,
        mutate: impl Fn(&mut Chain) -> R,
    ) -> Option<Result<R, persistent::file::Error>> {
        self.0
            .chains
            .mutate(chain_id, mutate)
            .map(|outcome| self.0.save().map(|()| outcome))
    }

    /// Removes and returns the owner of the given chain, erroring if the chain or owner is absent.
    pub fn forget_keys(&self, chain_id: ChainId) -> anyhow::Result<AccountOwner> {
        self.mutate(chain_id, |chain| chain.owner.take())
            .ok_or_else(|| anyhow::anyhow!("nonexistent chain `{chain_id}`"))??
            .ok_or_else(|| anyhow::anyhow!("keypair not found for chain `{chain_id}`"))
    }

    /// Writes the wallet to its file.
    pub fn save(&self) -> Result<(), persistent::file::Error> {
        self.0.save()
    }

    /// Returns the number of chains in the wallet.
    pub fn num_chains(&self) -> usize {
        self.0.chains.items().len()
    }

    /// Returns the IDs of all chains in the wallet.
    pub fn chain_ids(&self) -> Vec<ChainId> {
        self.0.chains.chain_ids()
    }

View on GitHub (pinned to 6c226ddcb3)

Solutions

  1. List the chains actually present: linera wallet show (or wallet.chain_ids()) and confirm the target ID
  2. Verify you are using the right wallet file: check --wallet path / LINERA_WALLET and the chain's network (devnet vs testnet)
  3. Re-add the chain before forgetting (linera wallet add-chain ...) if keys were removed earlier
  4. Double-check the full ChainId string for typos or missing characters

Example fix

// before
let owner = wallet.forget_keys(chain_id)?; // chain never added -> error

// after
if !wallet.chain_ids().contains(&chain_id) {
    anyhow::bail!("chain {chain_id} not in this wallet; available: {:?}", wallet.chain_ids());
}
let owner = wallet.forget_keys(chain_id)?;
Defensive patterns

Strategy: validation

Validate before calling

// Check membership before mutating
let ids = wallet.chain_ids();
if !ids.contains(&chain_id) {
    anyhow::bail!("chain {chain_id} not in wallet; have: {ids:?}");
}
let owner = wallet.forget_keys(chain_id)?;

Try / catch

match wallet.forget_keys(chain_id) {
    Ok(owner) => Ok(Some(owner)),
    Err(e) if e.to_string().contains("nonexistent chain") => {
        // nothing to do; treat as no-op for idempotent scripts
        Ok(None)
    }
    Err(e) => Err(e),
}

Prevention

When it happens

Trigger: Calling wallet.forget_keys(chain_id) with a chain ID that was never added, was already forgotten, belongs to a different wallet file, or was mistyped/truncated on the CLI.

Common situations: Running linera wallet forget-keys after the chain was removed by a previous operation; pointing LINERA_WALLET at the wrong wallet.json; passing a testnet chain ID to a devnet wallet; copy-paste error in the 64-hex-character chain ID.

Related errors


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