linera-io/linera-protocol · error · WorkerError

InvalidSigner

InvalidSigner

Error message

Operations in the block are not authenticated by the proper owner: {0}

What it means

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.

Source

Thrown at linera-core/src/chain_worker/state.rs:2540

        let chain = &self.chain;
        // Check if the chain is ready for this new block proposal.
        chain.tip_state.get().verify_block_chaining(block)?;
        // Check the epoch.
        let (epoch, committee) = chain.current_committee().await?;
        check_block_epoch(epoch, block.chain_id, block.epoch)?;
        let policy = committee.policy().clone();
        block.check_proposal_size(policy.maximum_block_proposal_size)?;
        // Check the authentication of the block.
        ensure!(
            chain.manager.can_propose(&owner, proposal.content.round),
            WorkerError::InvalidOwner
        );
        let old_round = self.chain.manager.current_round();
        match original_proposal {
            None => {
                if let Some(signer) = block.authenticated_owner {
                    // Check the authentication of the operations in the new block.
                    ensure!(signer == owner, WorkerError::InvalidSigner(owner));
                }
            }
            Some(OriginalProposal::Regular { certificate }) => {
                // Verify that this block has been validated by a quorum before.
                certificate.check(&committee)?;
            }
            Some(OriginalProposal::Fast(signature)) => {
                let original_proposal = BlockProposal {
                    content: ProposalContent {
                        block: content.block.clone(),
                        round: Round::Fast,
                        outcome: None,
                    },
                    signature: *signature,
                    original_proposal: None,
                };
                let super_owner = original_proposal.owner();
                ensure!(

View on GitHub (pinned to 6c226ddcb3)

Solutions

  1. Sign the proposal with the same account recorded in block.authenticated_owner.
  2. If the operations need no owner authentication, leave authenticated_owner as None.
  3. When reusing a block built elsewhere, rebuild the operation authentication under your own owner before signing.

Example fix

// before: block authenticated by app_owner, proposal signed by chain_owner
let block = builder.with_authenticated_owner(app_owner).build()?;
let proposal = block.into_proposal(&chain_owner_key);

// after: authenticate and propose with the same owner
let block = builder.with_authenticated_owner(chain_owner).build()?;
let proposal = block.into_proposal(&chain_owner_key);
Defensive patterns

Strategy: validation

Validate before calling

if let Some(signer) = block.authenticated_owner {
    ensure!(
        signer == proposal.owner(),
        WorkerError::InvalidSigner(proposal.owner())
    );
}

Try / catch

match node.handle_block_proposal(proposal).await {
    Err(NodeError::WorkerError(err)) if matches!(*err, WorkerError::InvalidSigner(_)) => {
        // Re-sign: make the proposal signer equal block.authenticated_owner,
        // or clear authenticated_owner if the operations need no owner auth.
    }
    result => result,
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Understand the failure class

Related errors


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