{"record":{"id":"831674cec2128240","repo":"nautechsystems/nautilus_trader","slug":"failed-to-derive-order-hash-e","errorCode":null,"errorMessage":"Failed to derive order hash: {e}","messagePattern":"Failed to derive order hash: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/adapters/polymarket/src/execution/order_builder.rs","lineNumber":224,"sourceCode":"            anyhow::bail!(\n                \"Polymarket market BUY amount {} pUSD truncates to zero at {LOT_SIZE_SCALE} decimal places\",\n                amount.normalize(),\n            );\n        }\n\n        let (maker_amount, taker_amount) =\n            compute_market_maker_taker_amounts(price, amount, side, tick_decimals);\n        self.build_and_sign(token_id, side, maker_amount, taker_amount, \"0\", neg_risk)\n    }\n\n    /// Computes the Polymarket order ID for a signed CLOB V2 order.\n    pub fn expected_order_id(\n        &self,\n        order: &PolymarketOrder,\n        neg_risk: bool,\n    ) -> anyhow::Result<VenueOrderId> {\n        let hash = order_hash(order, neg_risk)\n            .map_err(|e| anyhow::anyhow!(\"Failed to derive order hash: {e}\"))?;\n        let order_id = format!(\"{hash:#x}\");\n        Ok(VenueOrderId::from(order_id.as_str()))\n    }\n\n    /// Validates a limit order before building, returning a denial reason if invalid.\n    pub fn validate_limit_order(order: &OrderAny) -> Result<(), OrderDeniedReason> {\n        if order.is_reduce_only() {\n            return Err(validation_failed(\n                \"Reduce-only orders not supported on Polymarket\",\n            ));\n        }\n\n        if order.order_type() != OrderType::Limit {\n            return Err(OrderDeniedReason::UnsupportedOrderType {\n                order_type: order.order_type(),\n            });\n        }\n","sourceCodeStart":206,"sourceCodeEnd":242,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/polymarket/src/execution/order_builder.rs#L206-L242","documentation":"expected_order_id computes the EIP-712/keccak order hash via order_hash(order, neg_risk) to derive the venue order ID. When hash computation fails (malformed order fields, invalid salt/expiration encoding, or signer/wallet construction problems), the underlying error is wrapped as \"Failed to derive order hash: {e}\".","triggerScenarios":"Calling expected_order_id with a PolymarketOrder whose fields cannot be encoded per the CLOB EIP-712 schema, or with an incorrect neg_risk flag relative to the market, or when the signing wallet/key material is invalid.","commonSituations":"Passing neg_risk=false for a neg-risk market (or vice versa); orders built outside the normal builder path with missing maker/salt fields; corrupted or misconfigured private key used by the signer.","solutions":["Read the wrapped inner error ({e}) — it names the exact encoding or wallet failure to fix.","Ensure the order was built by PolymarketOrderBuilder::build_* so all EIP-712 fields (salt, maker, signer, expiration, neg_risk) are populated.","Verify the neg_risk flag matches the market being traded."],"exampleFix":"// before\nlet id = builder.expected_order_id(&hand_built_order, false)?; // hand-built, missing fields\n// after\nlet poly_order = builder.build_limit_order(&order, ...)?; // builder populates all hash inputs\nlet id = builder.expected_order_id(&poly_order, market_neg_risk)?;","handlingStrategy":"try-catch","validationCode":"if order.maker.is_empty() || order.salt.is_empty() || order.signature.is_empty() { return Err(\"order missing EIP-712 fields\".into()); }","typeGuard":"fn is_hashable(order: &PolymarketOrder) -> bool {\n    !order.maker.is_empty() && !order.signer.is_empty() && !order.salt.is_empty()\n}","tryCatchPattern":"match builder.expected_order_id(&order, neg_risk) {\n    Ok(id) => id,\n    Err(e) => { tracing::error!(\"order hash derivation failed: {e:#}\"); return Err(e); }\n}","preventionTips":["Only derive order IDs from orders produced by PolymarketOrderBuilder.","Verify neg_risk per market before hashing.","Log the full error chain ({e:#} with anyhow) to see the root cause."],"tags":["polymarket","eip712","order-hash","signing"],"backgroundTag":"signature-generation-failed","analyzedSha":"18893faf8b356be3320add8de2f861b0b647cf06","analyzedAt":"2026-09-08T20:49:34.690Z","contentChangedAt":"2026-09-08T20:49:34.690Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}