nautechsystems/nautilus_trader · error
invalid quantity `{value}`: {e}
Error message
invalid quantity `{value}`: {e} What it means
parse_quantity parses the input string with Decimal::from_str before any quantity checks. This error means the string is not a valid decimal number — bad characters, empty string, thousands separators, multiple decimal points, or other formats rust_decimal cannot parse. The raw value is embedded in the message.
Source
Thrown at crates/adapters/lighter/src/common/parse.rs:118
}
/// Converts a decimal string into a non-negative Nautilus [`Quantity`].
///
/// Zero is allowed because Lighter sends zero-size book levels to delete
/// existing orders.
///
/// # Errors
///
/// Returns an error if the string is not a decimal, if `precision` exceeds
/// [`MAX_DECIMALS`], if the value is negative, or if the resulting quantity
/// is out of range.
pub fn parse_quantity(value: &str, precision: u8) -> anyhow::Result<Quantity> {
anyhow::ensure!(
precision <= MAX_DECIMALS,
"size precision {precision} exceeds maximum {MAX_DECIMALS}",
);
let decimal =
Decimal::from_str(value).map_err(|e| anyhow::anyhow!("invalid quantity `{value}`: {e}"))?;
anyhow::ensure!(decimal.is_sign_positive(), "negative quantity `{value}`");
Quantity::from_decimal_dp(decimal, precision)
.map_err(|e| anyhow::anyhow!("invalid quantity `{value}` at precision {precision}: {e}"))
}
/// Converts a [`Decimal`] into a Nautilus [`Price`] at the requested precision.
///
/// Use this when the wire value has already been deserialized as a [`Decimal`]
/// (the standard pattern for model fields tagged with `deserialize_decimal`).
///
/// # Errors
///
/// Returns an error if `precision` exceeds [`MAX_DECIMALS`] or if the value
/// is out of [`Price`] range.
pub fn price_from_decimal(value: Decimal, precision: u8) -> anyhow::Result<Price> {
anyhow::ensure!(
precision <= MAX_DECIMALS,
"price precision {precision} exceeds maximum {MAX_DECIMALS}",View on GitHub (pinned to 18893faf8b)
Solutions
- Normalize the string first: trim, strip currency/ticker suffixes and thousands separators, convert locale decimal commas to dots.
- Confirm you are passing the raw wire value exactly as Lighter sends it (plain decimal string).
- If the field is optional, check for the sentinel/absent case before calling and skip parsing.
- Deserialize to Decimal via the adapter's deserialize_decimal helper and use Quantity::from_decimal_dp-based paths instead of strings.
Example fix
// before
let qty = parse_quantity(raw_size, precision)?;
// after
if raw_size.is_empty() || raw_size == "none" { return Ok(Quantity::zero(precision)); }
let qty = parse_quantity(raw_size.trim(), precision)?; Defensive patterns
Strategy: try-catch
Validate before calling
fn is_plain_decimal(s: &str) -> bool {
let s = s.trim();
!s.is_empty()
&& s.chars().all(|c| c.is_ascii_digit() || c == '.' || c == '-' || c == '+')
&& s.matches('.').count() <= 1
} Try / catch
match parse_quantity(raw, precision) {
Ok(q) => q,
Err(e) if e.to_string().starts_with("invalid quantity") && !e.to_string().contains("negative") => {
tracing::warn!(raw = %raw, "unparseable quantity string; skipping");
return Ok(None);
}
Err(e) => return Err(e.into()),
} Prevention
- Check optional/absent fields for sentinel values before calling the parser
- Pass the exact raw wire string with no display or locale formatting
- Handle empty strings explicitly (they will not parse) rather than relying on the parser
- Prefer Decimal-typed deserialization paths over strings where the wire format allows
When it happens
Trigger: Calling parse_quantity with a non-decimal string — e.g. "", "none", "1.5e3" variants rejected by rust_decimal, "1,000.5", "0.5 BTC", or a null-like sentinel string from the payload.
Common situations: Upstream responses where optional size fields are serialized as sentinel strings; display-formatted quantities; locale-formatted numbers (comma decimal separator); wiring the wrong field into the parser.
Understand the failure class
Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.
Related errors
- invalid price `{value}`: {e}
- Failed to parse fallback quantity for ord_id={}, sz='{}': {e
- Failed to parse filled quantity for ord_id={}, acc_fill_sz='
- Failed to parse base quantity for ord_id={}, sz='{}': {e}
- invalid signed E18 integer for {field}: {value}
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/5634d558034e5e66.
Report an issue: GitHub.