linera-io/linera-protocol · error
should execute block with OpenChain operations
Error message
should execute block with OpenChain operations
What it means
execute_open_chains_operations (linera-client/src/client_context.rs:1286) submits a batch of OpenChain operations and calls ClientOutcome::expect on the result. ChainClient::execute_operations returns ClientOutcome<ConfirmedBlockCertificate>: Committed, WaitForTimeout (this client is not the leader of the current consensus round), or Conflict (another block was already committed at the next height). expect panics on anything except Committed, so this fires when the block could not be immediately committed during benchmark chain creation.
Source
Thrown at linera-client/src/client_context.rs:1307
owners: Vec<AccountOwner>,
) -> Result<ConfirmedBlockCertificate, Error> {
let operations: Vec<_> = owners
.iter()
.map(|owner| {
let config = OpenChainConfig {
ownership: ChainOwnership::single_super(*owner),
account: AccountOwner::CHAIN,
balance,
application_permissions: Default::default(),
};
Operation::system(SystemOperation::OpenChain(config))
})
.collect();
info!("Executing {} OpenChain operations", operations.len());
Ok(chain_client
.execute_operations(operations, vec![])
.await?
.expect("should execute block with OpenChain operations"))
}
/// Supplies fungible tokens to the chains.
async fn supply_fungible_tokens(
&mut self,
key_pairs: &[(ChainId, AccountOwner)],
application_id: ApplicationId,
) -> Result<(), Error> {
let default_chain_id = self.default_chain();
let default_key = self
.wallet()
.get(default_chain_id)
.await
.unwrap()
.unwrap()
.owner
.unwrap();
// This should be enough to run the benchmark at 1M TPS for an hour.View on GitHub (pinned to 6c226ddcb3)
Solutions
- Ensure only one client process operates the wallet/default chain at a time; stop stale benchmark processes before starting a new run.
- Wait for in-flight blocks and the current round to finalize, then retry the benchmark command.
- If embedding, replace the expect with a match on ClientOutcome that sleeps until RoundTimeout.timestamp and retries, or resynchronizes on Conflict.
- Keep the default chain under single ownership during benchmark setup so leadership is unambiguous.
Example fix
// before
Ok(chain_client
.execute_operations(operations, vec![])
.await?
.expect("should execute block with OpenChain operations"))
// after
match chain_client.execute_operations(operations, vec![]).await? {
ClientOutcome::Committed(certificate) => Ok(certificate),
ClientOutcome::WaitForTimeout(timeout) => {
tokio::time::sleep_until(timeout.timestamp.into()).await;
// retry the batch
}
ClientOutcome::Conflict(certificate) => {
// another block landed at this height: resynchronize and re-prepare
}
} Defensive patterns
Strategy: retry
Type guard
fn is_committed<T>(outcome: &ClientOutcome<T>) -> bool {
matches!(outcome, ClientOutcome::Committed(_))
} Try / catch
// Instead of .expect, handle all three outcomes; retry is the correct strategy:
loop {
match chain_client.execute_operations(operations.clone(), vec![]).await? {
ClientOutcome::Committed(cert) => return Ok(cert),
ClientOutcome::WaitForTimeout(t) => tokio::time::sleep_until(t.timestamp.into()).await,
ClientOutcome::Conflict(_) => { /* resynchronize chain, re-derive operations, retry */ }
}
} Prevention
- Run exactly one client/wallet process per chain; serialize benchmark runs.
- Wait for prior runs' blocks to finalize (chain height settles) before starting benchmark preparation.
- Keep benchmark chains under single ownership so WaitForTimeout cannot occur.
When it happens
Trigger: Running benchmark preparation (prepare_for_benchmark / make_benchmark_chains flow) when the default chain's current round is led by another owner: a second client process operating the same chain/wallet, a leftover run still committing blocks, or multi-owner ownership where this client lost leadership.
Common situations: Two benchmark or client processes pointed at the same wallet or chain concurrently; re-running benchmarks before the previous run's blocks finished committing; chain ownership changed to multiple owners so WaitForTimeout becomes possible.
Related errors
- should execute block with Transfer operations
- default chain requested but none set
- No non-admin chain specified in wallet with no non-admin cha
- owner should be different from spender
- invalid block export configuration: {message}
AI-assisted analysis of linera-io/linera-protocol@6c226ddcb3 (2026-08-22).
Data as JSON: /api/errors/9dccf9c4621b920b.
Report an issue: GitHub.