nautechsystems/nautilus_trader · error
invalid candle high: {e}
Error message
invalid candle high: {e} What it means
parse_ws_bar converts the candle's high decimal into a Price at the instrument's price_precision via Price::from_decimal_dp. When that conversion fails the error is wrapped as 'invalid candle high', indicating the venue value cannot be represented at the configured precision.
Source
Thrown at crates/adapters/lighter/src/websocket/parse.rs:402
/// Parses a Lighter WebSocket candle into a Nautilus [`Bar`] with `ts_event` set to the bar open.
///
/// # Errors
///
/// Returns an error if the OHLCV decimals overflow the instrument's precision, or if the
/// timestamp cannot be converted.
pub fn parse_ws_bar(
instrument: &InstrumentAny,
candle: &LighterWsCandle,
resolution: LighterCandleResolution,
ts_init: UnixNanos,
) -> anyhow::Result<Bar> {
let price_precision = instrument.price_precision();
let size_precision = instrument.size_precision();
let open = Price::from_decimal_dp(candle.o, price_precision)
.map_err(|e| anyhow::anyhow!("invalid candle open: {e}"))?;
let high = Price::from_decimal_dp(candle.h, price_precision)
.map_err(|e| anyhow::anyhow!("invalid candle high: {e}"))?;
let low = Price::from_decimal_dp(candle.l, price_precision)
.map_err(|e| anyhow::anyhow!("invalid candle low: {e}"))?;
let close = Price::from_decimal_dp(candle.c, price_precision)
.map_err(|e| anyhow::anyhow!("invalid candle close: {e}"))?;
let volume = Quantity::from_decimal_dp(candle.v, size_precision)
.map_err(|e| anyhow::anyhow!("invalid candle volume: {e}"))?;
let t_ms = u64::try_from(candle.t)
.map_err(|_| anyhow::anyhow!("negative candle timestamp: {}", candle.t))?;
let ts_event = parse_millis_to_nanos(t_ms)?;
let bar_type = BarType::new(
instrument.id(),
resolution.to_bar_spec(),
AggregationSource::External,
);
Bar::new_checked(bar_type, open, high, low, close, volume, ts_event, ts_init)View on GitHub (pinned to 18893faf8b)
Solutions
- Align instrument price_precision with the venue's real precision
- Pre-round candle.h to price_precision before conversion
- Inspect candle.h and the wrapped error to find the bad value
- Verify the instrument registration matches the subscribed market
Example fix
// before let high = Price::from_decimal_dp(candle.h, price_precision)?; // after let high = Price::from_decimal_dp(candle.h.round_dp(price_precision as u32), price_precision)?;
Defensive patterns
Strategy: validation
Validate before calling
let high = candle.h.round_dp(instrument.price_precision() as u32);
Try / catch
match parse_ws_bar(candle, instrument, ...) {
Err(e) if e.to_string().contains("invalid candle high") => {
log::warn!("bad candle high {}, skipping bar: {e}", candle.h);
}
other => other?,
} Prevention
- Align price_precision with venue metadata
- Pre-quantize candle.h before Price construction
- Log raw candle payloads on parse failure
When it happens
Trigger: Candle high decimal with more fractional digits than price_precision, or otherwise invalid (negative/malformed) high value in the WebSocket candle message.
Common situations: Instrument precision configured too low; venue changing tick formatting; wrong instrument mapped to the candle stream.
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
- invalid candle open: {e}
- invalid candle low: {e}
- invalid candle close: {e}
- invalid candle volume: {e}
- invalid candle open: {e}
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/15f0989aaa18bb54.
Report an issue: GitHub.