{"record":{"id":"6333e93c9c0c3461","repo":"nautechsystems/nautilus_trader","slug":"ax-timestamp-must-be-non-negative-was-seconds","errorCode":null,"errorMessage":"AX timestamp must be non-negative, was {seconds}","messagePattern":"AX timestamp must be non-negative, was (.+?)","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/adapters/architect_ax/src/common/parse.rs","lineNumber":46,"sourceCode":"};\nuse nautilus_model::{\n    data::BarSpecification,\n    enums::AggressorSide,\n    identifiers::{ClientOrderId, TradeId},\n    types::{Price, Quantity, fixed::FIXED_PRECISION, quantity::QuantityRaw},\n};\n\nuse super::enums::AxCandleWidth;\n\nconst NANOSECONDS_IN_SECOND: u64 = 1_000_000_000;\n\n/// Converts an AX epoch-seconds timestamp to [`UnixNanos`].\n///\n/// # Errors\n///\n/// Returns an error if `seconds` is negative (malformed data from AX).\npub fn ax_timestamp_s_to_unix_nanos(seconds: i64) -> anyhow::Result<UnixNanos> {\n    anyhow::ensure!(\n        seconds >= 0,\n        \"AX timestamp must be non-negative, was {seconds}\"\n    );\n    Ok(UnixNanos::from(seconds as u64 * NANOSECONDS_IN_SECOND))\n}\n\n/// Converts AX `ts` (seconds) + `tn` (nanoseconds) fields to [`UnixNanos`].\n///\n/// # Errors\n///\n/// Returns an error if `seconds` is negative (malformed data from AX).\npub fn ax_timestamp_stn_to_unix_nanos(seconds: i64, nanos: i64) -> anyhow::Result<UnixNanos> {\n    anyhow::ensure!(\n        seconds >= 0,\n        \"AX timestamp must be non-negative, was {seconds}\"\n    );\n    let nanos_part = nanos.max(0) as u64;\n    Ok(UnixNanos::from(","sourceCodeStart":28,"sourceCodeEnd":64,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/a4b06ed870971b5671d12754ea138a3ab99b1dec/crates/adapters/architect_ax/src/common/parse.rs#L28-L64","documentation":"ax_timestamp_s_to_unix_nanos converts an ArchitectHUB epoch-seconds field to UnixNanos and guards against negative seconds, which would denote a pre-1970 timestamp. Architect timestamps are always post-epoch, so a negative value means malformed or garbage data from the venue/feed, and the adapter refuses to fabricate a time.","triggerScenarios":"An inbound AX WebSocket message whose ts/seconds field decodes to a negative i64 (corrupted frame, decoding offset bug, or a test fixture with an uninitialised value) reaching ax_timestamp_s_to_unix_nanos.","commonSituations":"Almost exclusively an adapter/data-feed defect: protocol changes on Architect's side, a buffer misparse after an API update, or hand-crafted fixture data using -1 as a sentinel. End users cannot trigger it with valid config.","solutions":["Capture the offending raw message and report it to the nautilus_trader maintainers with the timestamp","If it comes from your own test fixtures, set non-negative epoch-seconds values","Check for an architect_ax adapter version mismatch with the live API and upgrade","Verify the feed account/environment is healthy (resync/reconnect) before suspecting local code"],"exampleFix":"// before (fixture)\nlet ts = ax_timestamp_s_to_unix_nanos(-1)?; // AX timestamp must be non-negative, was -1\n\n// after\nlet ts = ax_timestamp_s_to_unix_nanos(1_700_000_000)?;","handlingStrategy":"try-catch","validationCode":null,"typeGuard":"fn is_valid_ax_seconds(seconds: i64) -> bool {\n    (0..i64::MAX).contains(&seconds)\n}","tryCatchPattern":"// Rust: adapter-level handling\nmatch ax_timestamp_s_to_unix_nanos(ts) {\n    Ok(nanos) => nanos,\n    Err(e) => {\n        tracing::error!(\"dropping malformed AX message: {e}\");\n        return Ok(()); // skip the corrupt message, keep the stream alive\n    }\n}","preventionTips":["Record raw venue frames when integrating so malformed messages can be reproduced","Keep the architect_ax adapter pinned to a version matching the live API","Use realistic non-negative epoch values in fixtures"],"tags":["rust","architect","adapter","timestamp","malformed-data","venue-feed"],"backgroundTag":"negative-timestamp-rejected","analyzedSha":"a4b06ed870971b5671d12754ea138a3ab99b1dec","analyzedAt":"2026-08-16T22:54:50.089Z","schemaVersion":2},"datasetVersion":"2026-08-16T23:17:17.608Z"}