linera-io/linera-protocol · error · NodeError

Node returned a BlobsNotFound error with an empty list of mi

Error message

Node returned a BlobsNotFound error with an empty list of missing blob IDs

What it means

Raised by RemoteNode::check_blobs_not_found, used from send_confirmed_certificate and send_validated_certificate when a validator rejects a certificate with BlobsNotFound. The client validates the complaint: the missing-blob list must be non-empty. An empty BlobsNotFound violates the protocol (the validator must name the blobs it lacks), so the client rejects the response instead of looping forever trying to satisfy an unnamed requirement.

Source

Thrown at linera-core/src/remote_node.rs:292

        ensure!(
            expected_heights.is_empty(),
            NodeError::MissingCertificatesByHeights {
                chain_id,
                heights: expected_heights.into_iter().collect(),
            }
        );
        Ok(certificates)
    }

    /// Checks that requesting these blobs when trying to handle this certificate is legitimate,
    /// i.e. that there are no duplicates and the blobs are actually required.
    pub fn check_blobs_not_found<C: Certified>(
        &self,
        certificate: &C,
        blob_ids: &[BlobId],
    ) -> Result<(), NodeError> {
        ensure!(!blob_ids.is_empty(), NodeError::EmptyBlobsNotFound);
        let required = certificate.value().required_blob_ids();
        for blob_id in blob_ids {
            if !required.contains(blob_id) {
                info!(
                    address = self.address(),
                    %blob_id,
                    "validator requested blob but it is not required",
                );
                return Err(NodeError::UnexpectedEntriesInBlobsNotFound);
            }
        }
        let unique_missing_blob_ids = blob_ids.iter().copied().collect::<HashSet<_>>();
        if blob_ids.len() > unique_missing_blob_ids.len() {
            info!(
                address = self.address(),
                "blobs requested by validator contain duplicates",
            );
            return Err(NodeError::DuplicatesInBlobsNotFound);

View on GitHub (pinned to 6c226ddcb3)

Solutions

  1. Skip the offending validator and continue with the rest of the committee (blob delivery only needs working validators)
  2. Check validator versions — upgrade the one emitting malformed BlobsNotFound
  3. If behind a proxy, inspect whether it serializes the error payload losslessly
  4. Report the validator; an empty missing-list is a protocol violation
Defensive patterns

Strategy: fallback

Type guard

fn is_empty_blobs_not_found(err: &NodeError) -> bool {
    matches!(err, NodeError::EmptyBlobsNotFound)
}

Try / catch

match send_certificate_to_validator(cert, &node).await {
    Err(NodeError::EmptyBlobsNotFound) => {
        // Malformed complaint: skip this validator, the remaining quorum suffices.
        Ok(())
    }
    other => other,
}

Prevention

When it happens

Trigger: A buggy or malicious validator returns a BlobsNotFound error carrying an empty Vec<BlobId>; version drift where an older validator emits the error shape without the payload. Duplicates or blobs not actually required by the certificate are reported separately (DuplicatesInBlobsNotFound / UnexpectedEntriesInBlobsNotFound).

Common situations: Mixed validator versions during an upgrade where the error payload changed; adversarial validators trying to stall certificate delivery; regressions in validator proxy serialization dropping the inner vector.

Related errors


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