linera-io/linera-protocol · error · NodeError

Events not found: {0:?}

Error message

Events not found: {0:?}

What it means

Raised in RemoteNodeUpdater::send_block_proposal when a validator rejects a proposal with EventsNotFound: the client maps each missing event to its publishing chain, forwards those chains' certificates to the validator, and retries — but only for publisher chains it has not already sent. If the same EventsNotFound comes back and every publisher chain is already in publisher_chain_ids_sent, there is nothing new to forward: the local node itself cannot provide those events, so the error is surfaced with the original event IDs.

Source

Thrown at linera-core/src/updater.rs:665

                    self.send_chain_info_up_to_heights(
                        origin_heights,
                        CrossChainMessageDelivery::Blocking,
                    )
                    .await?;
                }
                Err(NodeError::EventsNotFound(event_ids)) => {
                    let mut publisher_heights = BTreeMap::new();
                    let chain_ids = event_ids
                        .iter()
                        .map(|event_id| event_id.chain_id)
                        .filter(|chain_id| !publisher_chain_ids_sent.contains(chain_id))
                        .collect::<BTreeSet<_>>();
                    tracing::debug!(
                        remote_node = self.remote_node.address(),
                        ?chain_ids,
                        "missing events; sending chains to validator",
                    );
                    ensure!(!chain_ids.is_empty(), NodeError::EventsNotFound(event_ids));
                    for chain_id in chain_ids {
                        let height = self
                            .local_node
                            .get_next_height_to_preprocess(chain_id)
                            .await?;
                        publisher_heights.insert(chain_id, height);
                        publisher_chain_ids_sent.insert(chain_id);
                    }
                    self.send_chain_info_up_to_heights(
                        publisher_heights,
                        CrossChainMessageDelivery::NonBlocking,
                    )
                    .await?;
                }
                Err(error @ NodeError::ChainError { .. }) => {
                    // The validator rejected the proposal because of its local chain
                    // manager state — most commonly an incompatible confirmed vote tied
                    // to a locking block we don't yet have. The caller should pull

View on GitHub (pinned to 6c226ddcb3)

Solutions

  1. Before proposing, run download_certificates on every publisher chain referenced by the block (the event IDs in the error tell you which chains) so the local node holds the events
  2. Use prepare_chain()/full chain sync so epoch and admin-chain events are available locally
  3. Retry after syncing: once local storage has the events, forwarding them to the validator succeeds
  4. If the events genuinely do not exist (e.g. wrong stream/index), fix the application's referenced stream indices
Defensive patterns

Strategy: retry

Validate before calling

// Before proposing, make sure the local node holds every publisher chain your block reads.
for publisher in block_publisher_chains(&block) {
    let local = client.local_node().chain_info(publisher).await?;
    // ensure local height covers the events your application references
    assert!(local.next_block_height > required_height[publisher]);
}

Type guard

fn events_not_found(err: &chain_client::Error) -> Option<&Vec<EventId>> {
    match err {
        chain_client::Error::RemoteNodeError(NodeError::EventsNotFound(ids)) => Some(ids),
        _ => None,
    }
}

Try / catch

match client.process_pending_block().await {
    Err(e) if let Some(ids) = events_not_found(&e) => {
        // ids tell you the publisher chains; download them, then retry.
        for chain in ids.iter().map(|id| id.chain_id).collect::<BTreeSet<_>>() {
            client.synchronize_chain_state_from_all_validators_for(chain).await?;
        }
        client.process_pending_block().await
    }
    other => other,
}

Prevention

When it happens

Trigger: The block being proposed reads events (streams, epoch events) from publisher chains whose certificates the local node does not hold; event streams referenced by an application whose publishing chain was never synced locally; validator needing admin-chain epoch events the client lacks.

Common situations: Applications subscribing to streams on other chains after a wallet restore; multi-chain apps where the destination client only has message bundles but not the full publisher history; validators requiring committee/epoch events the client never downloaded.

Related errors


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