{"record":{"id":"c8f02db4c251004a","repo":"nautechsystems/nautilus_trader","slug":"negative-candle-volume","errorCode":null,"errorMessage":"negative candle volume `{}`","messagePattern":"negative candle volume `(.+?)`","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/adapters/lighter/src/http/parse.rs","lineNumber":222,"sourceCode":"        \"non-positive candle close `{}`\",\n        candle.close\n    );\n\n    let timestamp_ms =\n        u64::try_from(candle.timestamp).context(\"negative Lighter candle timestamp\")?;\n    let ts_event = parse_millis_to_nanos(timestamp_ms)?;\n    let price_precision = instrument.price_precision();\n    let size_precision = instrument.size_precision();\n\n    let open = Price::from_decimal_dp(candle.open, price_precision)\n        .map_err(|e| anyhow::anyhow!(\"invalid candle open: {e}\"))?;\n    let high = Price::from_decimal_dp(candle.high, price_precision)\n        .map_err(|e| anyhow::anyhow!(\"invalid candle high: {e}\"))?;\n    let low = Price::from_decimal_dp(candle.low, price_precision)\n        .map_err(|e| anyhow::anyhow!(\"invalid candle low: {e}\"))?;\n    let close = Price::from_decimal_dp(candle.close, price_precision)\n        .map_err(|e| anyhow::anyhow!(\"invalid candle close: {e}\"))?;\n    anyhow::ensure!(\n        candle.volume_base.is_sign_positive(),\n        \"negative candle volume `{}`\",\n        candle.volume_base,\n    );\n    let volume = Quantity::from_decimal_dp(candle.volume_base, size_precision)\n        .map_err(|e| anyhow::anyhow!(\"invalid candle volume: {e}\"))?;\n\n    Bar::new_checked(bar_type, open, high, low, close, volume, ts_event, ts_init)\n        .context(\"failed to construct Bar from Lighter candle\")\n}\n\n/// Parses a Lighter historical funding row into a Nautilus [`FundingRateUpdate`].\n///\n/// Lighter returns `rate` as a magnitude and `direction` as the side paying\n/// the funding. Nautilus uses the conventional signed rate: positive when\n/// longs pay shorts and negative when shorts pay longs.\n///\n/// # Errors","sourceCodeStart":204,"sourceCodeEnd":240,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/lighter/src/http/parse.rs#L204-L240","documentation":"parse_candle_bar checks candle.volume_base with is_sign_positive and rejects negative (or NaN) base volume, since Bar volume is a non-negative Quantity. Negative volume indicates corrupt or mis-scaled upstream candle data. The offending value is embedded in the message.","triggerScenarios":"parse_candle_bar receiving a LighterCandle with volume_base < 0 (or NaN, which fails is_sign_positive) when parsing the candles endpoint via parse_bars.","commonSituations":"Upstream API glitches or sign/scaling changes in the volume field; fixtures with negative volumes; data feeds during exchange incidents.","solutions":["Filter candles with negative volume_base before parsing","Inspect the raw API response for negative or NaN volume values","Verify the adapter's volume field mapping matches the current Lighter API schema","Correct test fixtures to use non-negative volumes"],"exampleFix":"// before\nlet bars = candles.iter().map(|c| parse_candle_bar(c, ...)).collect::<Result<Vec<_>>>()?;\n// after\nlet bars = candles.iter().filter(|c| c.volume_base.is_sign_positive()).map(|c| parse_candle_bar(c, ...)).collect::<Result<Vec<_>>>()?;","handlingStrategy":"validation","validationCode":"if !candle.volume_base.is_sign_positive() {\n    return Err(anyhow::anyhow!(\"skip candle: negative volume {}\", candle.volume_base));\n}","typeGuard":"fn has_valid_volume(c: &LighterCandle) -> bool {\n    c.volume_base.is_sign_positive() && c.volume_base.is_finite()\n}","tryCatchPattern":"let bar = match parse_candle_bar(&candle, bar_type, instrument, ts_init) {\n    Ok(b) => b,\n    Err(e) if e.to_string().contains(\"negative candle volume\") => continue,\n    Err(e) => return Err(e),\n};","preventionTips":["Filter candles on volume_base.is_sign_positive() before parsing","Verify volume field mapping against the current Lighter API schema","Treat NaN as invalid (it fails is_sign_positive) and filter it too","Keep fixtures with realistic non-negative volumes"],"tags":["rust","data-validation","volume","candles"],"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-14T00:17:10.932Z"}