nautechsystems/nautilus_trader · error
Must have the `chain` field set
Error message
Must have the `chain` field set
What it means
Block::chain() unwraps the optional `chain` field and panics if set_chain() was never called. Blocks are created without a chain and the caller must set it before accessor use; this is an internal state invariant enforced at read time. It signals a construction-order bug, not invalid data.
Source
Thrown at crates/model/src/defi/data/block.rs:166
blob_gas_used: None,
excess_blob_gas: None,
l1_gas_price: None,
l1_gas_used: None,
l1_fee_scalar: None,
}
}
/// Returns the blockchain for this block.
///
/// # Panics
///
/// Panics if the `chain` has not been set.
#[must_use]
pub fn chain(&self) -> Blockchain {
if let Some(chain) = self.chain {
chain
} else {
panic!("Must have the `chain` field set")
}
}
pub fn set_chain(&mut self, chain: Blockchain) {
self.chain = Some(chain);
}
/// Sets the EIP-1559 base fee and returns `self` for chaining.
#[must_use]
pub fn with_base_fee(mut self, fee: U256) -> Self {
self.base_fee_per_gas = Some(fee);
self
}
/// Sets blob-gas metrics (EIP-4844) and returns `self` for chaining.
#[must_use]
pub fn with_blob_gas(mut self, used: U256, excess: U256) -> Self {
self.blob_gas_used = Some(used);View on GitHub (pinned to 18893faf8b)
Solutions
- Call block.set_chain(Blockchain::Ethereum) (or the relevant chain) immediately after constructing the Block
- Ensure the deserialization/builder path sets `chain` before any accessor use
- Restructure code so the chain is a constructor argument rather than set later
Example fix
// before let block = Block::default(); let chain = block.chain(); // panics // after let mut block = Block::default(); block.set_chain(Blockchain::Ethereum); let chain = block.chain();
Defensive patterns
Strategy: type-guard
Validate before calling
// Ensure chain is set before reading
fn chain_is_set(block: &Block) -> bool {
// if the field is exposed or via a builder check
true // otherwise track set_chain at construction time
} Type guard
fn chain_or_none(block: &Block) -> Option<Blockchain> {
std::panic::catch_unwind(|| block.chain()).ok()
} Try / catch
let chain = std::panic::catch_unwind(|| block.chain())
.unwrap_or(Blockchain::Ethereum); // or propagate an error instead Prevention
- Always call set_chain immediately after creating a Block
- Construct Blocks via a helper/builder that requires the chain argument
- In deserialization, map missing chain to an error instead of leaving None
When it happens
Trigger: Calling block.chain() on a Block built via default/new without calling set_chain(chain) first; deserialization paths that skip set_chain.
Common situations: Building blockchain data feeds where the chain is assigned later from a subscription context; copying a Block field-by-field and forgetting the chain; partially initialized objects in tests.
Understand the failure class
Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.
Related errors
- Native currency not specified for chain {}
- `InstrumentId` not applicable to `Block`
- Invalid factory address for DEX {name} on chain {chain} for
- Liquidity addition overflow: x={current}, y={y}, delta={delt
- Liquidity subtraction underflow: x={current}, y={y}, delta={
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/d76df55e2e30ed1b.
Report an issue: GitHub.