nautechsystems/nautilus_trader · error
Invalid negative quantity: {value}
Error message
Invalid negative quantity: {value} What it means
`decode_optional_quantity` converts an i64 Databento quantity into an `Option<Quantity>`: `i64::MAX` maps to `None` (undefined), non-negative values decode normally, and negative values are rejected because quantities in the Nautilus domain model can never be negative. The error surfaces when a Databento record carries a negative quantity that would corrupt downstream order/position logic.
Source
Thrown at crates/adapters/databento/src/decode/primitives.rs:328
/// Decodes a quantity from the given value, expressed in standard whole-number units.
#[inline(always)]
#[must_use]
pub fn decode_quantity(value: u64) -> Quantity {
quantity_from_whole(value)
}
/// Decodes a quantity from the given optional value, where `i64::MAX` indicates missing data.
///
/// # Errors
///
/// Returns an error if the quantity is negative.
#[inline(always)]
pub fn decode_optional_quantity(value: i64) -> anyhow::Result<Option<Quantity>> {
match value {
i64::MAX => Ok(None),
value if value >= 0 => Ok(Some(quantity_from_whole(value as u64))),
value => anyhow::bail!("Invalid negative quantity: {value}"),
}
}
/// Decodes a timestamp, returning an error if undefined.
///
/// Databento uses `u64::MAX` as `UNDEF_TIMESTAMP` sentinel for null timestamps.
///
/// # Errors
///
/// Returns an error if `value` is `u64::MAX` (undefined).
#[inline(always)]
pub fn decode_timestamp(value: u64, field_name: &str) -> anyhow::Result<UnixNanos> {
if value == dbn::UNDEF_TIMESTAMP {
anyhow::bail!("Missing required timestamp for `{field_name}`")
} else {
Ok(UnixNanos::from(value))
}
}View on GitHub (pinned to 18893faf8b)
Solutions
- Inspect the offending record and verify whether the negative value is a genuine data issue; exclude or correct the record.
- If the semantics of the field allow negatives (e.g. net change), decode it with a signed type instead of `decode_optional_quantity`.
- Pre-filter records: skip rows where the quantity field is negative before calling the decoder.
- Catch the anyhow error in the record-processing closure and log/skip rather than aborting the whole range request.
Example fix
// before
let qty = decode_optional_quantity(stat.quantity as i64)?;
// after
let qty = if (stat.quantity as i64) < 0 && stat.quantity as i64 != i64::MAX { None } else { decode_optional_quantity(stat.quantity as i64)? }; Defensive patterns
Strategy: validation
Validate before calling
fn quantity_valid(raw: i64) -> bool { raw == i64::MAX || raw >= 0 } Type guard
fn is_negative_quantity(v: i64) -> bool { v != i64::MAX && v < 0 } Try / catch
match decode_optional_quantity(raw) {
Ok(q) => use(q),
Err(e) => { log::warn!("bad quantity: {e}"); Quantity::default() }
} Prevention
- Reject or sanitize negative quantity fields in records before decoding.
- Remember the two sentinels: i64::MAX = undefined, negatives = invalid.
- Verify vendor data quality when statistics records report negative volumes.
When it happens
Trigger: `decode_optional_quantity(v)` called with `v < 0` (and not `i64::MAX`); typically via `decode_statistics_msg` when a statistics record contains a negative value quantity.
Common situations: Loading historical Databento statistics/definition data containing negative volume fields (data-quality issues or vendor encoding quirks), or feeding already-converted/scaled data back through the decoder so values appear negative.
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 negative multiplier: {v}
- AX requires whole contract quantities, was {}
- Order quantity must be at least 1 contract
- Order quantity must be positive
- Order quantity {quantity} is not exactly representable in {d
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/cfffe06489bee64b.
Report an issue: GitHub.