linera-io/linera-protocol · error · ExecutionError

EventsNotFound

EventsNotFound

Error message

ExecutionError::EventsNotFound(missing_events)

What it means

get_committee_hashes computes committee blob hashes for an epoch range: epoch 0 comes from the NetworkDescription, and every later epoch is read as an event from the admin chain's system epoch stream (EPOCH_STREAM_NAME). If any of those events cannot be loaded, all missing EventIds are collected and returned as EventsNotFound (lib.rs:627), failing chain initialization or committee resolution.

Source

Thrown at linera-execution/src/lib.rs:627

                        .ok_or_else(|| ExecutionError::EventsNotFound(vec![event_id]))?;
                    let event_data: EpochEventData = bcs::from_bytes(&event)?;
                    Ok((Epoch(epoch), event_data.blob_hash))
                }
            }),
        )
        .await;
        let missing_events = committee_hashes
            .iter()
            .filter_map(|result| {
                if let Err(ExecutionError::EventsNotFound(event_ids)) = result {
                    return Some(event_ids);
                }
                None
            })
            .flatten()
            .cloned()
            .collect::<Vec<_>>();
        ensure!(
            missing_events.is_empty(),
            ExecutionError::EventsNotFound(missing_events)
        );
        committee_hashes.into_iter().collect()
    }

    /// Returns whether a blob with the given ID is available.
    async fn contains_blob(&self, blob_id: BlobId) -> Result<bool, ViewError>;

    /// Returns whether an event with the given ID is available.
    async fn contains_event(&self, event_id: EventId) -> Result<bool, ViewError>;

    /// Adds the given blobs to the context, for use in tests.
    #[cfg(with_testing)]
    async fn add_blobs(
        &self,
        blobs: impl IntoIterator<Item = Blob> + Send,
    ) -> Result<(), ViewError>;

View on GitHub (pinned to 6c226ddcb3)

Solutions

  1. Sync the admin chain (or fetch the missing epoch-stream events from a peer) so the events exist in storage, then retry
  2. When operating from a checkpoint, restore with a blob and event set that includes the admin chain epoch events
  3. Verify the NetworkDescription's admin_chain_id matches the network you intend to join
  4. Bound the requested epoch range to epochs that actually exist on the admin chain
Defensive patterns

Strategy: retry

Validate before calling

// Pre-check that the epoch events exist before asking for committee hashes
async fn epoch_events_available(
    client: &Client,
    admin_chain: ChainId,
    range: RangeInclusive<Epoch>,
) -> Result<bool, ExecutionError> {
    for epoch in range.into_iter().filter(|e| e.0 > 0) {
        let event_id = EventId {
            chain_id: admin_chain,
            stream_id: StreamId::system(EPOCH_STREAM_NAME),
            index: epoch.0,
        };
        if client.get_event(event_id).await?.is_none() {
            return Ok(false);
        }
    }
    Ok(true)
}

if !epoch_events_available(client, admin_chain, range.clone()).await? {
    client.sync_admin_chain().await?; // fetch missing epoch events first
}

Type guard

fn is_events_not_found(err: &ExecutionError) -> bool {
    matches!(err, ExecutionError::EventsNotFound(_))
}

Try / catch

let mut attempt = 0;
loop {
    match runtime.committee_for_epoch(range.clone()).await {
        Ok(c) => break Ok(c),
        Err(ref e) if is_events_not_found(e) && attempt < MAX_ATTEMPTS => {
            // storage gap: sync the admin chain epoch events, then retry
            client.sync_admin_chain().await?;
            attempt += 1;
            continue;
        }
        Err(e) => break Err(e),
    }
}

Prevention

When it happens

Trigger: initialize_chain or committee_for_epoch asks for epochs whose admin-chain epoch events are absent from the node's storage: not synced, pruned, or published on a different admin chain than the NetworkDescription declares.

Common situations: Starting a validator or client without syncing the admin chain; epoch events pruned after a checkpoint restore that did not retain the epoch stream; a misconfigured NetworkDescription with the wrong admin_chain_id; requesting an epoch above what the network has created.

Related errors


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