{"record":{"id":"7b1ff348072b0d6c","repo":"nautechsystems/nautilus_trader","slug":"field-must-be-non-negative-was-value","errorCode":null,"errorMessage":"{field} must be non-negative, was {value}","messagePattern":"(.+?) must be non-negative, was (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/adapters/bybit/src/websocket/parse.rs","lineNumber":676,"sourceCode":"            delta,\n            gamma,\n            vega,\n            theta,\n            rho: 0.0, // Bybit doesn't provide rho\n        },\n        mark_iv: Some(mark_iv),\n        bid_iv: Some(bid_iv),\n        ask_iv: Some(ask_iv),\n        underlying_price: Some(underlying_price),\n        open_interest: Some(open_interest),\n        ts_event,\n        ts_init,\n    })\n}\n\npub(crate) fn parse_millis_i64(value: i64, field: &str) -> anyhow::Result<UnixNanos> {\n    if value < 0 {\n        Err(anyhow::anyhow!(\"{field} must be non-negative, was {value}\"))\n    } else {\n        let nanos = (value as u64)\n            .checked_mul(NANOSECONDS_IN_MILLISECOND)\n            .ok_or_else(|| anyhow::anyhow!(\"millisecond timestamp overflowed\"))?;\n        Ok(UnixNanos::from(nanos))\n    }\n}\n\n/// Parses a WebSocket kline payload into a [`Bar`].\n///\n/// # Errors\n///\n/// Returns an error if price or volume fields cannot be parsed or if the bar cannot be constructed.\npub fn parse_ws_kline_bar(\n    kline: &BybitWsKline,\n    instrument: &InstrumentAny,\n    bar_type: BarType,\n    timestamp_on_close: bool,","sourceCodeStart":658,"sourceCodeEnd":694,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/bybit/src/websocket/parse.rs#L658-L694","documentation":"Field sanity guard parse_millis_i64 used across Bybit WebSocket parsing: venue timestamps must be non-negative; a negative millis value indicates a malformed message and is rejected before conversion to UnixNanos.","triggerScenarios":"Any WebSocket message (orderbook, trade tick, quote, orderbook deltas) carrying a negative millisecond timestamp field (e.g. `ts`, `transaction_time`) passed through parse_millis_i64.","commonSituations":"Clock skew producing negative derived deltas; upstream sending sentinel values like -1 for 'unknown'; corrupted or synthetic test payloads with negative times.","solutions":["Inspect the raw WebSocket payload and the field named in the error for the negative value","Treat -1/unknown sentinels as absent and skip or substitute a local receive timestamp","Check for clock-skew arithmetic that subtracts a larger timestamp from a smaller one before calling the parser"],"exampleFix":"// before: passes sentinel straight through\nlet ts = parse_millis_i64(raw.ts, \"ts\")?;\n// after: filter sentinels first\nlet ts = if raw.ts < 0 { recv_time_ns } else { parse_millis_i64(raw.ts, \"ts\")? };","handlingStrategy":"validation","validationCode":"def valid_millis(v: int) -> bool:\n    return v >= 0","typeGuard":"def is_non_negative(v) -> bool:\n    return isinstance(v, int) and v >= 0","tryCatchPattern":"match parse_millis_i64(raw.ts, \"ts\") {\n    Err(e) if e.to_string().contains(\"must be non-negative\") => use_recv_time_fallback(),\n    other => other?,\n}","preventionTips":["Treat negative/sentinel timestamps as missing upstream","Sanity-check derived timestamps for clock skew","Validate timestamps at the message-decode boundary"],"tags":["rust","bybit","websocket","timestamp","validation"],"backgroundTag":"invalid-argument-value","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"}