linera-io/linera-protocol · error · ChainError

Closed chains cannot have operations, accepted messages or e

Error message

Closed chains cannot have operations, accepted messages or empty blocks

What it means

If the chain's system.closed flag is set (via the admin CloseChain operation), execute_block only admits blocks whose transactions are all rejected incoming messages (has_only_rejected_messages, linera-chain/src/chain.rs:112-122 and 1330-1332). ClosedChain fires for any operation, any accepted message, or an empty transaction list on a closed chain — closure is terminal for writes.

Source

Thrown at linera-chain/src/chain.rs:1331

            chain_timestamp <= block.timestamp,
            ChainError::InvalidBlockTimestamp {
                parent: chain_timestamp,
                new: block.timestamp
            }
        );
        ensure!(!block.transactions.is_empty(), ChainError::EmptyBlock);

        ensure!(
            block.published_blob_ids()
                == published_blobs
                    .iter()
                    .map(|blob| blob.id())
                    .collect::<BTreeSet<_>>(),
            ChainError::InternalError("published_blobs mismatch".to_string())
        );

        if *self.execution_state.system.closed.get() {
            ensure!(block.has_only_rejected_messages(), ChainError::ClosedChain);
        }

        Self::check_app_permissions(
            self.execution_state
                .system
                .application_permissions
                .get()
                .await?,
            &block,
        )?;

        ensure!(
            !block
                .transactions
                .iter()
                .skip(1)
                .any(Transaction::is_checkpoint),
            ChainError::CheckpointPreconditionFailed(

View on GitHub (pinned to 6c226ddcb3)

Solutions

  1. Query the chain's state and check the closed flag before submitting anything
  2. If you only need to bounce queued incoming messages, build blocks whose bundles all use MessageAction::Reject
  3. Closure is irreversible — move activity to a new chain and repoint clients to it

Example fix

// before: submitting an operation blindly
client.submit_block(vec![Transaction::ExecuteOperation(op)]).await?; // ClosedChain

// after: gate on the closed flag; only rejects are admissible
let info = client.chain_info(chain_id).await?;
if info.info.system_closed {
    return Err(anyhow::anyhow!("chain {chain_id} is closed"));
}
client.submit_block(vec![Transaction::ExecuteOperation(op)]).await?;
Defensive patterns

Strategy: validation

Validate before calling

// Before submitting anything to a chain, check its lifecycle state:
let info = client.chain_info(chain_id).await?;
if info.info.system_closed {
    anyhow::bail!("chain {chain_id} is closed; only rejected-message blocks are allowed");
}
// and for closed chains, ensure every bundle uses MessageAction::Reject:
assert!(block.has_only_rejected_messages());

Type guard

fn admissible_on_closed_chain(block: &ProposedBlock) -> bool {
    // mirrors ProposedBlock::has_only_rejected_messages (data_types/mod.rs:112)
    block.transactions.iter().all(|t| matches!(
        t,
        Transaction::ReceiveMessages(IncomingBundle { action: MessageAction::Reject, .. })
    ))
}

Try / catch

match result {
    Err(ChainError::ClosedChain) => {
        // permanent for this chain: stop submitting, retire clients, or move to a new chain
    }
    other => other?,
}

Prevention

When it happens

Trigger: Submitting operations or accepted-message blocks to a chain that was closed earlier; a client or faucet still holding the chain's key trying to transfer after closure; automated jobs that keep proposing to a retired chain.

Common situations: Retiring a chain but leaving background clients (bots, cron jobs, faucet) running; user apps sending to a closed recipient; test chains closed between phases with fixtures reused afterwards.

Related errors


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