{"record":{"id":"2d73d73800d16717","repo":"linera-io/linera-protocol","slug":"invalidsigner","errorCode":"InvalidSigner","errorMessage":"Operations in the block are not authenticated by the proper owner: {0}","messagePattern":"Operations in the block are not authenticated by the proper owner: (.+?)","errorType":"validation","errorClass":"WorkerError","httpStatus":null,"severity":"error","filePath":"linera-core/src/chain_worker/state.rs","lineNumber":2540,"sourceCode":"        let chain = &self.chain;\n        // Check if the chain is ready for this new block proposal.\n        chain.tip_state.get().verify_block_chaining(block)?;\n        // Check the epoch.\n        let (epoch, committee) = chain.current_committee().await?;\n        check_block_epoch(epoch, block.chain_id, block.epoch)?;\n        let policy = committee.policy().clone();\n        block.check_proposal_size(policy.maximum_block_proposal_size)?;\n        // Check the authentication of the block.\n        ensure!(\n            chain.manager.can_propose(&owner, proposal.content.round),\n            WorkerError::InvalidOwner\n        );\n        let old_round = self.chain.manager.current_round();\n        match original_proposal {\n            None => {\n                if let Some(signer) = block.authenticated_owner {\n                    // Check the authentication of the operations in the new block.\n                    ensure!(signer == owner, WorkerError::InvalidSigner(owner));\n                }\n            }\n            Some(OriginalProposal::Regular { certificate }) => {\n                // Verify that this block has been validated by a quorum before.\n                certificate.check(&committee)?;\n            }\n            Some(OriginalProposal::Fast(signature)) => {\n                let original_proposal = BlockProposal {\n                    content: ProposalContent {\n                        block: content.block.clone(),\n                        round: Round::Fast,\n                        outcome: None,\n                    },\n                    signature: *signature,\n                    original_proposal: None,\n                };\n                let super_owner = original_proposal.owner();\n                ensure!(","sourceCodeStart":2522,"sourceCodeEnd":2558,"githubUrl":"https://github.com/linera-io/linera-protocol/blob/6c226ddcb332ef55118dc8d0aafbd093d5420899/linera-core/src/chain_worker/state.rs#L2522-L2558","documentation":"When a block's operations need owner authentication, the block records their signer in block.authenticated_owner. For a plain proposal (no original proposal attached), try_handle_block_proposal requires that signer to be exactly the owner who signed the proposal. InvalidSigner is raised when the two accounts differ: the operations were authenticated by someone other than the proposer.","triggerScenarios":"A client that builds the block (authenticating its operations) with one account but signs the BlockProposal with another; re-signing a proposed block originally created by a different owner without clearing or updating authenticated_owner.","commonSituations":"Multi-key wallets that split block building from proposal signing; applications whose operations are authenticated by an application account while the chain owner signs the proposal.","solutions":["Sign the proposal with the same account recorded in block.authenticated_owner.","If the operations need no owner authentication, leave authenticated_owner as None.","When reusing a block built elsewhere, rebuild the operation authentication under your own owner before signing."],"exampleFix":"// before: block authenticated by app_owner, proposal signed by chain_owner\nlet block = builder.with_authenticated_owner(app_owner).build()?;\nlet proposal = block.into_proposal(&chain_owner_key);\n\n// after: authenticate and propose with the same owner\nlet block = builder.with_authenticated_owner(chain_owner).build()?;\nlet proposal = block.into_proposal(&chain_owner_key);","handlingStrategy":"validation","validationCode":"if let Some(signer) = block.authenticated_owner {\n    ensure!(\n        signer == proposal.owner(),\n        WorkerError::InvalidSigner(proposal.owner())\n    );\n}","typeGuard":null,"tryCatchPattern":"match node.handle_block_proposal(proposal).await {\n    Err(NodeError::WorkerError(err)) if matches!(*err, WorkerError::InvalidSigner(_)) => {\n        // Re-sign: make the proposal signer equal block.authenticated_owner,\n        // or clear authenticated_owner if the operations need no owner auth.\n    }\n    result => result,\n}","preventionTips":["Use one key for both authenticating operations and signing the proposal, or none at all.","Do not hand a built block to a different owner to sign without rebuilding its authentication.","Assert signer == owner in client code before submitting; the error only surfaces the expected owner."],"tags":["rust","linera","blockchain","signing","authorization","ownership"],"backgroundTag":"signer-mismatch","analyzedSha":"6c226ddcb332ef55118dc8d0aafbd093d5420899","analyzedAt":"2026-08-22T22:49:09.787Z","schemaVersion":2},"datasetVersion":"2026-08-23T01:17:44.959Z"}