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.
///
/// # ErrorsView on GitHub (pinned to 18893faf8b)
Solutions
- Retry against the same node; transient decode issues may clear after sync.
- Use a different, healthy gRPC endpoint.
- Align tendermint/comet proto crate versions with the node's CometBFT release so Header decodes into the expected field.
- 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
- Maintain a secondary RPC endpoint for block queries
- Retry once before failing the whole operation
- Monitor node health/sync status of configured endpoints
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
- The latest block is empty
- Cannot create sign doc: {e}
- {e}
- Query account request failure, account should exist
- Simulation response does not contain gas info
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/2ed76a5647482da9.
Report an issue: GitHub.