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

  1. Call block.set_chain(Blockchain::Ethereum) (or the relevant chain) immediately after constructing the Block
  2. Ensure the deserialization/builder path sets `chain` before any accessor use
  3. 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

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


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