{"record":{"id":"f5b327a2fa0e7019","repo":"linera-io/linera-protocol","slug":"default-chain-requested-but-none-set","errorCode":null,"errorMessage":"default chain requested but none set","messagePattern":"default chain requested but none set","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"linera-client/src/client_context.rs","lineNumber":397,"sourceCode":"    pub fn wallet(&self) -> &Env::Wallet {\n        self.client.wallet()\n    }\n\n    /// Returns the ID of the admin chain.\n    pub fn admin_chain_id(&self) -> ChainId {\n        self.client.admin_chain_id()\n    }\n\n    /// Retrieve the default account. Current this is the common account of the default\n    /// chain.\n    pub fn default_account(&self) -> Account {\n        Account::chain(self.default_chain())\n    }\n\n    /// Retrieve the default chain.\n    pub fn default_chain(&self) -> ChainId {\n        self.default_chain\n            .expect(\"default chain requested but none set\")\n    }\n\n    /// Returns the lowest non-admin chain ID in the wallet.\n    pub async fn first_non_admin_chain(&self) -> Result<ChainId, Error> {\n        let admin_chain_id = self.admin_chain_id();\n        let chain_ids = self\n            .wallet()\n            .chain_ids()\n            .try_filter(|chain_id| futures::future::ready(*chain_id != admin_chain_id))\n            .try_collect::<Vec<ChainId>>()\n            .await\n            .map_err(Error::wallet)?;\n        Ok(chain_ids\n            .into_iter()\n            .min()\n            .expect(\"No non-admin chain specified in wallet with no non-admin chain\"))\n    }\n","sourceCodeStart":379,"sourceCodeEnd":415,"githubUrl":"https://github.com/linera-io/linera-protocol/blob/6c226ddcb332ef55118dc8d0aafbd093d5420899/linera-client/src/client_context.rs#L379-L415","documentation":"linera-client's ClientContext stores the default chain as an Option<ChainId> and default_chain() (linera-client/src/client_context.rs:395) unwraps it unconditionally. The panic fires when the context was built without a default chain - typically a wallet that has no user chain selected, such as a fresh wallet or one holding only the admin chain. Every API that needs an implicit chain (default_account, ownership, change_ownership, set_preferred_owner, the benchmark helpers, supply_fungible_tokens) routes through this accessor, so any of them can trigger it.","triggerScenarios":"Calling default_account(), ownership(), change_ownership(), set_preferred_owner(), or the benchmark preparation flow while wallet/config left default_chain as None. Concretely: running a wallet-dependent CLI command against a wallet whose only entry is the admin chain, or constructing ClientContext programmatically with default_chain: None (as the unit-test stub in linera-client/src/unit_tests/client_context.rs does).","commonSituations":"Fresh wallet created but no user chain claimed from the faucet yet; a wallet whose default chain entry was removed or lost after migration; CLI wallet generation that omitted a default chain assignment; embedding linera-client and forgetting to derive the default chain from wallet.chain_ids() before use.","solutions":["Claim or create a user chain (e.g. via the faucet) so the wallet holds a non-admin chain, then set it as the default chain in the wallet.","Re-run the command with an explicit --chain-id so default_chain() is never consulted.","Inspect the wallet (linera wallet show) and assign a default chain pointing at an existing chain entry.","If embedding linera-client, populate the default chain from wallet.chain_ids() before calling any default-chain-dependent API."],"exampleFix":"// before\nlet account = context.default_account(); // panics: \"default chain requested but none set\"\n\n// after\n// Option<ChainId> field on the context options; check it first\nmatch context_options.default_chain {\n    Some(chain_id) => Account::chain(chain_id),\n    None => return Err(anyhow::anyhow!(\"no default chain in wallet; pass --chain-id or claim a chain first\")),\n}","handlingStrategy":"validation","validationCode":"// Before any default-chain-dependent call, verify the wallet has a usable chain:\nlet chain_ids: Vec<ChainId> = wallet.chain_ids().try_collect().await?;\nlet has_user_chain = chain_ids.iter().any(|id| *id != client_context.admin_chain_id());\nif !has_user_chain {\n    anyhow::bail!(\"wallet holds no non-admin chain; claim one from the faucet or pass --chain-id\");\n}","typeGuard":"fn has_default_chain(ctx: &ClientContext) -> bool {\n    // default_chain is Option<ChainId> on the context/options; treat None as unsafe to call\n    ctx_default_chain_option(ctx).is_some()\n}\n\nfn ctx_default_chain_option(ctx: &ClientContext) -> Option<ChainId> {\n    // if the field is not directly accessible, mirror it via wallet state:\n    // Some(chain) only when the wallet marks a chain as default/preferred.\n    ctx.default_chain\n}","tryCatchPattern":"// Panics are not Result-based; when embedding, isolate with catch_unwind at the boundary:\nlet result = std::panic::catch_unwind(AssertUnwindSafe(|| context.default_account()));\nmatch result {\n    Ok(account) => { /* proceed */ }\n    Err(_) => return Err(anyhow::anyhow!(\"no default chain configured in wallet\")),\n}","preventionTips":["Always pass an explicit --chain-id in scripts instead of relying on the implicit default chain.","After wallet creation, verify with `linera wallet show` that a default chain is set before running commands.","When embedding linera-client, populate the default chain from wallet.chain_ids() at context construction and fail fast if empty."],"tags":["linera-client","wallet","default-chain","panic","rust"],"backgroundTag":"missing-required-configuration","analyzedSha":"6c226ddcb332ef55118dc8d0aafbd093d5420899","analyzedAt":"2026-08-22T22:49:09.787Z","schemaVersion":2},"datasetVersion":"2026-08-23T01:17:44.959Z"}