{"record":{"id":"7bedc41b474ca22c","repo":"nautechsystems/nautilus_trader","slug":"gtd-stop-limit-requires-expire-time","errorCode":null,"errorMessage":"GTD STOP_LIMIT requires expire_time","messagePattern":"GTD STOP_LIMIT requires expire_time","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/adapters/coinbase/src/http/client.rs","lineNumber":1703,"sourceCode":"            let stop_price = trigger\n                .ok_or_else(|| anyhow::anyhow!(\"STOP_LIMIT order requires trigger_price\"))?;\n            let direction = match side {\n                OrderSide::Buy => CoinbaseStopDirection::StopUp,\n                OrderSide::Sell => CoinbaseStopDirection::StopDown,\n            };\n\n            match time_in_force {\n                TimeInForce::Gtc => Ok(OrderConfiguration::StopLimitGtc(StopLimitGtc {\n                    stop_limit_stop_limit_gtc: StopLimitGtcParams {\n                        base_size: qty,\n                        limit_price,\n                        stop_price,\n                        stop_direction: direction,\n                    },\n                })),\n                TimeInForce::Gtd => {\n                    let expire = expire_time\n                        .ok_or_else(|| anyhow::anyhow!(\"GTD STOP_LIMIT requires expire_time\"))?;\n                    Ok(OrderConfiguration::StopLimitGtd(StopLimitGtd {\n                        stop_limit_stop_limit_gtd: StopLimitGtdParams {\n                            base_size: qty,\n                            limit_price,\n                            stop_price,\n                            stop_direction: direction,\n                            end_time: format_rfc3339_from_nanos(expire)?,\n                        },\n                    }))\n                }\n                _ => anyhow::bail!(\"Unsupported TIF {time_in_force} for STOP_LIMIT on Coinbase\"),\n            }\n        }\n        other => anyhow::bail!(\"Unsupported order type for Coinbase: {other}\"),\n    }\n}\n\n#[cfg(test)]","sourceCodeStart":1685,"sourceCodeEnd":1721,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/coinbase/src/http/client.rs#L1685-L1721","documentation":"For a Good-Til-Date (GTD) STOP_LIMIT order, Coinbase's StopLimitGtd configuration requires an expiration timestamp. When time_in_force is GTD, the adapter reads the order's expire_time; if it is absent it cannot build the GTD order and raises this error. Other TIFs (e.g. GTC) do not need it.","triggerScenarios":"Submitting OrderType::StopLimit with TimeInForce::Gtd while the order's expire_time/ts_init-derived expiry is None; constructing a GTD stop-limit order without an expiry argument; leaving expire_time unset when copying a GTC order and switching TIF to GTD.","commonSituations":"Changing an order's TIF from GTC to GTD without adding an expiry; time-based strategy logic computing expiry after order creation but before it is attached; factory calls that default expire_time to None.","solutions":["Set expire_time (UTC datetime) on the order when using GTD, e.g. factory time_in_force=GTD with expire_time parameter.","Use TimeInForce::Gtc instead if the order should not expire.","Ensure the expire_time is in the future and formatted per the adapter's expectations (nanosecond timestamp)."],"exampleFix":"// before\nlet order = factory.stop_limit(..., time_in_force=TimeInForce.Gtd, expire_time=None);\n// after\nlet order = factory.stop_limit(\n    ...,\n    time_in_force=TimeInForce.Gtd,\n    expire_time=UnixNanos::from(u64::try_from(expiry_ts_nanos)?), // required for GTD\n);","handlingStrategy":"validation","validationCode":"fn ensure_gtd_expiry(order: &OrderRequest) -> Result<(), String> {\n    if order.time_in_force == TimeInForce::Gtd && order.expire_time.is_none() {\n        return Err(format!(\"{}: GTD requires expire_time\", order.client_order_id));\n    }\n    Ok(())\n}\nensure_gtd_expiry(&req)?;","typeGuard":"fn has_expiry(o: &OrderRequest) -> bool { o.time_in_force != TimeInForce::Gtd || o.expire_time.is_some() }","tryCatchPattern":null,"preventionTips":["Compute expire_time from strategy logic at order creation time, never later.","Default to GTC when no expiry is needed.","Keep a TIF-to-required-fields map in your order-construction layer."],"tags":["order-submission","time-in-force","missing-expiry"],"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"}