{"record":{"id":"d76df55e2e30ed1b","repo":"nautechsystems/nautilus_trader","slug":"must-have-the-chain-field-set","errorCode":null,"errorMessage":"Must have the `chain` field set","messagePattern":"Must have the `chain` field set","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/model/src/defi/data/block.rs","lineNumber":166,"sourceCode":"            blob_gas_used: None,\n            excess_blob_gas: None,\n            l1_gas_price: None,\n            l1_gas_used: None,\n            l1_fee_scalar: None,\n        }\n    }\n\n    /// Returns the blockchain for this block.\n    ///\n    /// # Panics\n    ///\n    /// Panics if the `chain` has not been set.\n    #[must_use]\n    pub fn chain(&self) -> Blockchain {\n        if let Some(chain) = self.chain {\n            chain\n        } else {\n            panic!(\"Must have the `chain` field set\")\n        }\n    }\n\n    pub fn set_chain(&mut self, chain: Blockchain) {\n        self.chain = Some(chain);\n    }\n\n    /// Sets the EIP-1559 base fee and returns `self` for chaining.\n    #[must_use]\n    pub fn with_base_fee(mut self, fee: U256) -> Self {\n        self.base_fee_per_gas = Some(fee);\n        self\n    }\n\n    /// Sets blob-gas metrics (EIP-4844) and returns `self` for chaining.\n    #[must_use]\n    pub fn with_blob_gas(mut self, used: U256, excess: U256) -> Self {\n        self.blob_gas_used = Some(used);","sourceCodeStart":148,"sourceCodeEnd":184,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/model/src/defi/data/block.rs#L148-L184","documentation":"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.","triggerScenarios":"Calling block.chain() on a Block built via default/new without calling set_chain(chain) first; deserialization paths that skip set_chain.","commonSituations":"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.","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"],"exampleFix":"// before\nlet block = Block::default();\nlet chain = block.chain(); // panics\n// after\nlet mut block = Block::default();\nblock.set_chain(Blockchain::Ethereum);\nlet chain = block.chain();","handlingStrategy":"type-guard","validationCode":"// Ensure chain is set before reading\nfn chain_is_set(block: &Block) -> bool {\n    // if the field is exposed or via a builder check\n    true // otherwise track set_chain at construction time\n}","typeGuard":"fn chain_or_none(block: &Block) -> Option<Blockchain> {\n    std::panic::catch_unwind(|| block.chain()).ok()\n}","tryCatchPattern":"let chain = std::panic::catch_unwind(|| block.chain())\n    .unwrap_or(Blockchain::Ethereum); // or propagate an error instead","preventionTips":["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"],"tags":["rust","panic","defi","uninitialized-field"],"backgroundTag":"internal-invariant-violation","analyzedSha":"18893faf8b356be3320add8de2f861b0b647cf06","analyzedAt":"2026-09-08T20:49:34.690Z","contentChangedAt":"2026-09-08T20:49:34.690Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}