{"record":{"id":"a80967164c6c52dc","repo":"linera-io/linera-protocol","slug":"cannot-process-inbox-for-follow-only-chain-chain","errorCode":null,"errorMessage":"Cannot process inbox for follow-only chain {chain_id}. Use `linera assign` to take ownership of the chain first.","messagePattern":"Cannot process inbox for follow-only chain (.+?)\\. Use `linera assign` to take ownership of the chain first\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"linera-service/src/cli/main.rs","lineNumber":526,"sourceCode":"                context.update_wallet_from_client(&chain_client).await?;\n                let time_total = time_start.elapsed();\n                info!(\n                    \"Synchronized chain information in {} ms\",\n                    time_total.as_millis()\n                );\n            }\n\n            ProcessInbox { chain_id } => {\n                let mut context = options\n                    .create_client_context(storage, wallet, keystore)\n                    .await?;\n                let chain_id = chain_id.unwrap_or_else(|| context.default_chain());\n                let follow_only = context\n                    .wallet()\n                    .get(chain_id)\n                    .is_some_and(|chain| chain.is_follow_only());\n                if follow_only {\n                    anyhow::bail!(\n                        \"Cannot process inbox for follow-only chain {chain_id}. \\\n                         Use `linera assign` to take ownership of the chain first.\"\n                    );\n                }\n                let chain_client = context.make_chain_client(chain_id).await?;\n                info!(\"Processing the inbox of chain {}\", chain_id);\n                let time_start = Instant::now();\n                let certificates = context.process_inbox(&chain_client).await?;\n                let time_total = time_start.elapsed();\n                info!(\n                    \"Processed incoming messages with {} blocks in {} ms\",\n                    certificates.len(),\n                    time_total.as_millis()\n                );\n            }\n\n            QueryShardInfo { chain_id } => {\n                let context = options","sourceCodeStart":508,"sourceCodeEnd":544,"githubUrl":"https://github.com/linera-io/linera-protocol/blob/6c226ddcb332ef55118dc8d0aafbd093d5420899/linera-service/src/cli/main.rs#L508-L544","documentation":"'linera process-inbox' refuses to run for a chain the wallet tracks as follow-only: the wallet has the chain's id and can read it, but holds no signing key, so it cannot propose blocks to process incoming bundles. The fix is built into the message: 'linera assign' registers a new owner key on the chain, converting it to a full (ownable) chain.","triggerScenarios":"Running ProcessInbox with --chain-id (or as default chain) pointing to a chain added read-only (e.g. tracked for observation, a publicly-readable chain like a service chain), where wallet.get(chain_id).is_follow_only() is true. The check runs before make_chain_client, so no network work happens first.","commonSituations":"Following a shared/application chain with 'linera track' or via a wallet import that marks it follow-only, then trying to operate on it; switching a workflow from watching to acting without taking ownership; default_chain pointing at the tracked chain after wallet reordering.","solutions":["Take ownership: run 'linera assign --chain-id <chain_id>' to register your key on the chain (requires the chain to permit assignment), then re-run process-inbox.","If you did not intend to process that chain, target a chain you own: pass --chain-id of an owned chain, or set your default chain.","If the chain should be ownable but is wrongly marked follow-only (wallet import quirk), inspect the wallet entry and fix its state or re-import.","Automations should check the follow-only flag in the wallet before invoking process-inbox on arbitrary chains."],"exampleFix":"# before\n$ linera process-inbox --chain-id 745a... \nError: Cannot process inbox for follow-only chain 745a.... Use `linera assign` to take ownership of the chain first.\n\n# after\n$ linera assign --chain-id 745a...\n$ linera process-inbox --chain-id 745a...","handlingStrategy":"validation","validationCode":"// Before process-inbox, check wallet state:\nlet chain = context.wallet().get(chain_id)\n    .with_context(|| format!(\"chain {chain_id} not in wallet\"))?;\nanyhow::ensure!(!chain.is_follow_only(),\n    \"chain {chain_id} is follow-only; run `linera assign` first\");","typeGuard":null,"tryCatchPattern":"// Match on the message and convert to the remediation:\nmatch run_process_inbox(chain_id).await {\n    Err(e) if e.to_string().contains(\"follow-only chain\") => {\n        eprintln!(\"run: linera assign --chain-id {chain_id}\");\n        return Err(e);\n    }\n    other => other,\n}","preventionTips":["Automations should filter candidate chains by !is_follow_only() from the wallet before operating.","After tracking a read-only chain, set --default-chain to an owned chain to avoid accidental targeting."],"tags":["linera-service","cli","permissions","follow-only","chain-management","rust"],"backgroundTag":"insufficient-permissions","analyzedSha":"6c226ddcb332ef55118dc8d0aafbd093d5420899","analyzedAt":"2026-08-22T22:49:09.787Z","schemaVersion":2},"datasetVersion":"2026-08-23T01:17:44.959Z"}