nautechsystems/nautilus_trader · error · anyhow::Error

The block doesn't contain a header

Error message

The block doesn't contain a header

What it means

latest_block_height extracts the header from the latest block response to read its height; if the block carries no header the library cannot derive a Height and raises this error. The header is required metadata on any well-formed Tendermint/CometBFT block, so this signals a malformed or mis-decoded response.

Source

Thrown at crates/adapters/dydx/src/grpc/client.rs:400

            .base
            .get_latest_block(req)
            .await?
            .into_inner()
            .sdk_block
            .ok_or_else(|| anyhow::anyhow!("The latest block is empty"))?;
        Ok(latest_block)
    }

    /// Query for the latest block height.
    ///
    /// # Errors
    ///
    /// Returns an error if the query fails.
    pub async fn latest_block_height(&mut self) -> Result<Height, anyhow::Error> {
        let latest_block = self.latest_block().await?;
        let header = latest_block
            .header
            .ok_or_else(|| anyhow::anyhow!("The block doesn't contain a header"))?;
        let height = Height(header.height.try_into()?);
        Ok(height)
    }

    /// Query for all perpetual markets.
    ///
    /// # Errors
    ///
    /// Returns an error if the query fails.
    pub async fn get_perpetuals(&mut self) -> Result<Vec<Perpetual>, anyhow::Error> {
        let req = QueryAllPerpetualsRequest { pagination: None };
        let response = self.perpetuals.all_perpetuals(req).await?.into_inner();
        Ok(response.perpetual)
    }

    /// Query for all CLOB pairs.
    ///
    /// # Errors

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Retry against the same node; transient decode issues may clear after sync.
  2. Use a different, healthy gRPC endpoint.
  3. Align tendermint/comet proto crate versions with the node's CometBFT release so Header decodes into the expected field.
  4. Log the raw GetLatestBlock response to confirm whether header is absent server-side or lost in decoding.

Example fix

// before
let height = client.latest_block_height().await?;
// after: fall back to an alternate source
let height = match client.latest_block_height().await {
    Ok(h) => h,
    Err(e) if e.to_string().contains("doesn't contain a header") => {
        let h = grpc_status_client.latest_block_height().await?;
        h
    }
    Err(e) => return Err(e),
};
Defensive patterns

Strategy: fallback

Try / catch

let height = client.latest_block_height().await
    .or_else(|_| fallback_client.latest_block_height().await)?;

Prevention

When it happens

Trigger: Calling latest_block_height when latest_block returned a block whose `header` field is None — proto decode mismatch or a degraded node response.

Common situations: Same endpoint/version issues as the empty-block error: stale or syncing node, incompatible proto definitions where the header lands in a different oneof variant.

Related errors


AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08). Data as JSON: /api/errors/2ed76a5647482da9. Report an issue: GitHub.