{"record":{"id":"4db5498c954b0c7a","repo":"nautechsystems/nautilus_trader","slug":"start-date-must-be-before-end-date","errorCode":null,"errorMessage":"Start date must be before end date","messagePattern":"Start date must be before end date","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/adapters/interactive_brokers/src/historical/client.rs","lineNumber":243,"sourceCode":"        &self,\n        bar_specifications: Vec<&str>,\n        end_date_time: Timestamp,\n        start_date_time: Option<Timestamp>,\n        duration: Option<&str>,\n        contracts: Option<Vec<Contract>>,\n        instrument_ids: Option<Vec<InstrumentId>>,\n        use_rth: bool,\n        timeout: u64,\n    ) -> anyhow::Result<Vec<Bar>> {\n        // Validate inputs\n        if start_date_time.is_some() && duration.is_some() {\n            anyhow::bail!(\"Either start_date_time or duration should be provided, not both\");\n        }\n\n        if let Some(start) = start_date_time\n            && start >= end_date_time\n        {\n            anyhow::bail!(\"Start date must be before end date\");\n        }\n\n        if let Some(duration) = duration {\n            duration.parse::<historical::Duration>().with_context(|| {\n                format!(\"duration must be in format: 'int S|D|W|M|Y', was '{duration}'\")\n            })?;\n        }\n\n        let contracts = contracts.unwrap_or_default();\n        let instrument_ids = instrument_ids.unwrap_or_default();\n\n        if contracts.is_empty() && instrument_ids.is_empty() {\n            anyhow::bail!(\"Either contracts or instrument_ids must be provided\");\n        }\n\n        // Convert instrument IDs to contracts using instrument provider\n        let mut all_contracts = contracts;\n","sourceCodeStart":225,"sourceCodeEnd":261,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/interactive_brokers/src/historical/client.rs#L225-L261","documentation":"request_bars validates that the optional start_date_time is strictly earlier than end_date_time. An equal or later start would produce an empty or inverted IB history window, so the call is rejected up front.","triggerScenarios":"Calling request_bars with start_date_time >= end_date_time (e.g. both set to the same day boundary, or start/end swapped).","commonSituations":"Computing start/end from UTC timestamps with timezone mix-ups; accidental argument swap; using 'now' for both fields; off-by-one when flooring end to the day while start carries a time-of-day.","solutions":["Ensure start_date_time < end_date_time before calling; swap them if inverted.","Truncate or floor start below the end boundary if they collide at a day edge.","Drop start_date_time and pass a duration string instead if the exact window is flexible."],"exampleFix":"// before\nclient.request_bars(&[\"1-DAY-LAST\"], end_ts, Some(end_ts), None, None, Some(ids), true, 60).await?;\n// after\nlet start = end_ts - jiff::SignedDuration::from_hours(24);\nclient.request_bars(&[\"1-DAY-LAST\"], end_ts, Some(start), None, None, Some(ids), true, 60).await?;","handlingStrategy":"validation","validationCode":"debug_assert!(start < end, \"start must preced end\");\nif start >= end { return Err(\"invalid bar window: start >= end\"); }","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Normalize all timestamps to UTC before comparing.","Clamp start to end - 1 tick when they collide.","Centralize window construction in one helper instead of ad-hoc timestamp math per call site."],"tags":["date-range","validation","rust","historical-data"],"backgroundTag":"invalid-date-format","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"}