{"record":{"id":"79ee378dadd89a56","repo":"nautechsystems/nautilus_trader","slug":"gtd-limit-requires-expire-time","errorCode":null,"errorMessage":"GTD LIMIT requires expire_time","messagePattern":"GTD LIMIT requires expire_time","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/adapters/coinbase/src/http/client.rs","lineNumber":1663,"sourceCode":"                    )\n                }\n            }\n        }\n        OrderType::Limit => {\n            let limit_price =\n                price.ok_or_else(|| anyhow::anyhow!(\"LIMIT order requires a price\"))?;\n\n            match time_in_force {\n                TimeInForce::Gtc => Ok(OrderConfiguration::LimitGtc(LimitGtc {\n                    limit_limit_gtc: LimitGtcParams {\n                        base_size: qty,\n                        limit_price,\n                        post_only,\n                    },\n                })),\n                TimeInForce::Gtd => {\n                    let expire = expire_time\n                        .ok_or_else(|| anyhow::anyhow!(\"GTD LIMIT requires expire_time\"))?;\n                    Ok(OrderConfiguration::LimitGtd(LimitGtd {\n                        limit_limit_gtd: LimitGtdParams {\n                            base_size: qty,\n                            limit_price,\n                            end_time: format_rfc3339_from_nanos(expire)?,\n                            post_only,\n                        },\n                    }))\n                }\n                TimeInForce::Fok => Ok(OrderConfiguration::LimitFok(LimitFok {\n                    limit_limit_fok: LimitFokParams {\n                        base_size: qty,\n                        limit_price,\n                    },\n                })),\n                _ => anyhow::bail!(\"Unsupported TIF {time_in_force} for LIMIT on Coinbase\"),\n            }\n        }","sourceCodeStart":1645,"sourceCodeEnd":1681,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/coinbase/src/http/client.rs#L1645-L1681","documentation":"This error is raised by `build_order_configuration` when a LIMIT order uses `TimeInForce::Gtd` (good-til-date) but no `expire_time` is provided. Coinbase's `LimitGtd` payload requires an `end_time`, so the adapter fails fast rather than submitting an order without an expiry. It indicates the order was marked GTD but the expiration timestamp was never set.","triggerScenarios":"Submitting a LIMIT order with time_in_force=Gtd and expire_time=None — e.g. a strategy selecting GTD without computing/passing the expiry timestamp (UnixNanos), or a default TIF of GTD applied without expiry configuration.","commonSituations":"Strategy configs where GTD is the default TIF but expiry is optional; end-of-session expiry logic that fails to set expire_time; porting GTD orders from venues where the exchange assigns a default expiry.","solutions":["Set a valid `expire_time` (UnixNanos) when constructing the GTD LIMIT order.","Fall back to TimeInForce::Gtc when no expiry is needed or available.","Validate at the strategy/order-factory level that GTD orders always carry expire_time.","Compute the expiry from a policy (e.g. session end or now + N hours) instead of leaving it unset."],"exampleFix":"// before\nlet order = factory.limit(instrument_id, Buy, qty, price, TimeInForce::Gtd); // no expire_time\n// after\nlet expire = factory.ts_now() + Duration::from_secs(8 * 3600).as_nanos() as u64;\nlet order = factory.limit_gtd(instrument_id, Buy, qty, price, expire);","handlingStrategy":"validation","validationCode":"fn validate_gtd(tif: TimeInForce, expire_time: Option<UnixNanos>) -> Result<(), String> {\n    match (tif, expire_time) {\n        (TimeInForce::Gtd, None) => Err(\"GTD LIMIT requires expire_time\".into()),\n        _ => Ok(()),\n    }\n}","typeGuard":null,"tryCatchPattern":"let tif = if expire_time.is_some() { TimeInForce::Gtd } else { TimeInForce::Gtc };\nmatch build_order_configuration(OrderType::Limit, side, qty, price, None, tif, expire_time, post_only, false, false) {\n    Ok(config) => submit(config),\n    Err(e) if e.to_string().contains(\"expire_time\") => { tracing::error!(\"GTD order without expiry\"); Err(e) }\n    Err(e) => return Err(e),\n}","preventionTips":["Make expire_time mandatory wherever TIF=Gtd is selected.","Default to GTC when no expiry policy is configured.","Compute expiries from a single policy function to avoid ad-hoc None values.","Add tests that GTD requests always include expire_time."],"tags":["coinbase","orders","gtd","missing-field","time-in-force"],"backgroundTag":"missing-required-argument","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"}