linera-io/linera-protocol · error · ChainError
UnexpectedBlockHeight
UnexpectedBlockHeight
Error message
Chain is expecting a next block at height {expected_block_height} but the given block is at height {found_block_height} instead What it means
process_validated_block requires the validated block's height to equal the chain's next_block_height exactly: validated certificates extend the chain one height at a time and must be applied in order. A certificate for a future height, or one for an already-passed height that is not covered by the skip paths, is rejected.
Source
Thrown at linera-core/src/chain_worker/state.rs:882
/// Processes a validated block issued for this multi-owner chain.
#[instrument(skip_all, fields(
chain_id = %self.chain_id(),
block_height = %certificate.block().header.height
))]
pub(crate) async fn process_validated_block(
&mut self,
certificate: ValidatedBlockCertificate,
) -> Result<(ChainInfoResponse, NetworkActions, BlockOutcome), WorkerError> {
let block = certificate.block();
let header = &block.header;
let height = header.height;
// Check that the chain is active and ready for this validated block.
// Verify the certificate. Returns a catch-all error to make client code more robust.
self.initialize_and_save_if_needed().await?;
let tip_state = self.chain.tip_state.get();
ensure!(
header.height == tip_state.next_block_height,
ChainError::UnexpectedBlockHeight {
expected_block_height: tip_state.next_block_height,
found_block_height: header.height,
}
);
let (epoch, committee) = self.chain.current_committee().await?;
check_block_epoch(epoch, header.chain_id, header.epoch)?;
certificate.check(&committee)?;
let already_committed_block = self.chain.tip_state.get().already_validated_block(height)?;
let should_skip_validated_block = || {
self.chain
.manager
.check_validated_block(&certificate)
.map(|outcome| outcome == manager::Outcome::Skip)
};
if already_committed_block || should_skip_validated_block()? {
// If we just processed the same pending block, return the chain info unchanged.View on GitHub (pinned to 6c226ddcb3)
Solutions
- Process validated (and confirmed) block certificates strictly in height order, one per height
- Query ChainInfo for next_block_height and submit the certificate that matches it
- Drop certificates below next_block_height — their blocks are already applied
Defensive patterns
Strategy: validation
Validate before calling
// Only deliver the certificate matching the chain's next height.
let info = client.chain_info(chain_id).await?;
let expected = info.manager.next_block_height;
match certificate.block().header.height.cmp(&expected) {
Ordering::Equal => client.submit_validated(certificate).await?,
Ordering::Less => { /* already applied; drop it */ }
Ordering::Greater => { /* fetch and submit certificates for the gap first */ }
} Type guard
fn is_unexpected_block_height(e: &ChainError) -> bool {
matches!(e, ChainError::UnexpectedBlockHeight { .. })
} Try / catch
match client.submit_validated(certificate).await {
Err(e) if matches!(e, ref x if x.is_unexpected_block_height()) => {
// Re-query next_block_height, deliver the missing heights in order, then retry.
}
other => other?,
} Prevention
- Deliver validated and confirmed certificates strictly in height order
- Derive the next expected height from fresh ChainInfo, not from local counters
- Drop certificates below next_block_height instead of resubmitting them
When it happens
Trigger: process_validated_block (from handle_validated_request) with a certificate whose block height differs from tip_state.next_block_height — skipping heights, delivering out of order, or replaying old certificates after the tip advanced.
Common situations: Out-of-order certificate delivery during chain synchronization; client resuming from stale local state; duplicate submission after the block was already confirmed via another path.
Related errors
- no signer found for owner ${owner}
- BlockHeightOverflow
- InvalidBlockChaining
- CannotRejectMessage
- Certificate justification commitment does not match its just
AI-assisted analysis of linera-io/linera-protocol@6c226ddcb3 (2026-08-22).
Data as JSON: /api/errors/377eea56fb225c51.
Report an issue: GitHub.