nautechsystems/nautilus_trader · error
non-positive candle close `{}`
Error message
non-positive candle close `{}` What it means
parse_candle_bar requires a candle's close price to be strictly positive. A non-positive close means the candle record from Lighter is invalid (placeholder, corrupt, or untraded market data) and cannot become a Bar. The message includes the offending value.
Source
Thrown at crates/adapters/lighter/src/http/parse.rs:202
instrument: &InstrumentAny,
ts_init: UnixNanos,
) -> anyhow::Result<Bar> {
anyhow::ensure!(
candle.open > Decimal::ZERO,
"non-positive candle open `{}`",
candle.open
);
anyhow::ensure!(
candle.high > Decimal::ZERO,
"non-positive candle high `{}`",
candle.high
);
anyhow::ensure!(
candle.low > Decimal::ZERO,
"non-positive candle low `{}`",
candle.low
);
anyhow::ensure!(
candle.close > Decimal::ZERO,
"non-positive candle close `{}`",
candle.close
);
let timestamp_ms =
u64::try_from(candle.timestamp).context("negative Lighter candle timestamp")?;
let ts_event = parse_millis_to_nanos(timestamp_ms)?;
let price_precision = instrument.price_precision();
let size_precision = instrument.size_precision();
let open = Price::from_decimal_dp(candle.open, price_precision)
.map_err(|e| anyhow::anyhow!("invalid candle open: {e}"))?;
let high = Price::from_decimal_dp(candle.high, price_precision)
.map_err(|e| anyhow::anyhow!("invalid candle high: {e}"))?;
let low = Price::from_decimal_dp(candle.low, price_precision)
.map_err(|e| anyhow::anyhow!("invalid candle low: {e}"))?;
let close = Price::from_decimal_dp(candle.close, price_precision)View on GitHub (pinned to 18893faf8b)
Solutions
- Filter candles with close <= 0 out before parsing
- Verify the Lighter API response contains real trade data for the interval
- Check market status (newly listed/delisted markets may return zeros)
- Correct fixture or mock data to positive values
Example fix
// before
let bar = parse_candle_bar(&candle, ...)?;
// after
if candle.close <= Decimal::ZERO { continue; }
let bar = parse_candle_bar(&candle, ...)?; Defensive patterns
Strategy: validation
Validate before calling
if candle.close <= Decimal::ZERO {
return Err(anyhow::anyhow!("skip candle: non-positive close {}", candle.close));
} Type guard
fn has_positive_ohlc(c: &LighterCandle) -> bool {
c.open > Decimal::ZERO && c.high > Decimal::ZERO && c.low > Decimal::ZERO && c.close > Decimal::ZERO
} Try / catch
let bar = match parse_candle_bar(&candle, bar_type, instrument, ts_init) {
Ok(b) => b,
Err(e) if e.to_string().contains("non-positive candle close") => continue,
Err(e) => return Err(e),
}; Prevention
- Pre-check all four OHLC values are positive before calling the parser
- Sanity-check upstream API responses during exchange incidents
- Use real (non-zeroed) sample data in tests
- Filter placeholder candles for newly listed or halted markets
When it happens
Trigger: parse_candle_bar receiving a LighterCandle with close <= 0 while converting candles via parse_bars.
Common situations: Empty/illiquid markets returning zeroed candles; upstream outages producing placeholder data; bad fixture data in tests.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- non-positive candle open `{}`
- non-positive candle high `{}`
- non-positive candle low `{}`
- negative candle volume `{}`
- Unsupported bar specification for AX: {step}-{:?}
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/cf2581c8c613b56e.
Report an issue: GitHub.