{"record":{"id":"1bf6f26ec57f74fa","repo":"nautechsystems/nautilus_trader","slug":"invalid-price-value-e","errorCode":null,"errorMessage":"invalid price `{value}`: {e}","messagePattern":"invalid price `(.+?)`: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/adapters/lighter/src/common/parse.rs","lineNumber":97,"sourceCode":"    let decimal = Decimal::new(ticks, u32::from(decimals));\n    Quantity::from_decimal_dp(decimal, decimals).map_err(|e| {\n        anyhow::anyhow!(\"Quantity overflow for ticks={ticks}, decimals={decimals}: {e}\")\n    })\n}\n\n/// Converts a decimal string into a Nautilus [`Price`] at the requested precision.\n///\n/// # Errors\n///\n/// Returns an error if the string is not a decimal, if `precision` exceeds\n/// [`MAX_DECIMALS`], or if the resulting value is out of range.\npub fn parse_price(value: &str, precision: u8) -> anyhow::Result<Price> {\n    anyhow::ensure!(\n        precision <= MAX_DECIMALS,\n        \"price precision {precision} exceeds maximum {MAX_DECIMALS}\",\n    );\n    let decimal =\n        Decimal::from_str(value).map_err(|e| anyhow::anyhow!(\"invalid price `{value}`: {e}\"))?;\n    Price::from_decimal_dp(decimal, precision)\n        .map_err(|e| anyhow::anyhow!(\"invalid price `{value}` at precision {precision}: {e}\"))\n}\n\n/// Converts a decimal string into a non-negative Nautilus [`Quantity`].\n///\n/// Zero is allowed because Lighter sends zero-size book levels to delete\n/// existing orders.\n///\n/// # Errors\n///\n/// Returns an error if the string is not a decimal, if `precision` exceeds\n/// [`MAX_DECIMALS`], if the value is negative, or if the resulting quantity\n/// is out of range.\npub fn parse_quantity(value: &str, precision: u8) -> anyhow::Result<Quantity> {\n    anyhow::ensure!(\n        precision <= MAX_DECIMALS,\n        \"size precision {precision} exceeds maximum {MAX_DECIMALS}\",","sourceCodeStart":79,"sourceCodeEnd":115,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/lighter/src/common/parse.rs#L79-L115","documentation":"parse_price first parses the input string with rust_decimal's Decimal::from_str. This error means the string is not a valid decimal number (bad characters, empty string, multiple dots, scientific notation beyond rust_decimal's acceptance, etc.), so no Price can be constructed. The raw value is included in the message for diagnosis.","triggerScenarios":"Calling parse_price with a string that Decimal::from_str cannot parse — e.g. \"\", \"N/A\", \"1,234.5\" (thousands separator), \"0x1F\", \"1.2.3\", or an already-formatted/annotated string like \"123.45 USD\".","commonSituations":"Feeding a display-formatted price into the parser; locale-formatted numbers with comma decimal separators; upstream payloads where a numeric field was serialized as a localized or annotated string; stringly-typed config values for limit prices.","solutions":["Validate/normalize the string first: trim whitespace, strip currency symbols and thousands separators, and replace locale decimal commas with dots.","Ensure the field is the raw decimal string as sent by Lighter's API (e.g. \"123.45\"), not a human-formatted rendering.","If the value arrives as JSON, deserialize it with the adapter's deserialize_decimal helper and use price_from_decimal instead of string parsing.","Log the offending value from the error message and add a unit test pinning the expected wire format."],"exampleFix":"// before\nlet price = parse_price(\"1,234.50 USD\", precision)?;\n// after\nlet normalized = raw.trim().replace(\",\", \"\");\nlet price = parse_price(&normalized, precision)?;","handlingStrategy":"try-catch","validationCode":"fn is_plain_decimal(s: &str) -> bool {\n    let s = s.trim();\n    !s.is_empty()\n        && s.chars().all(|c| c.is_ascii_digit() || c == '.' || c == '-' || c == '+')\n        && s.matches('.').count() <= 1\n}","typeGuard":null,"tryCatchPattern":"match parse_price(raw, precision) {\n    Ok(p) => p,\n    Err(e) if e.to_string().starts_with(\"invalid price\") => {\n        tracing::warn!(raw = %raw, \"unparseable price string; skipping\");\n        return Ok(None);\n    }\n    Err(e) => return Err(e.into()),\n}","preventionTips":["Pass the raw wire string untouched — no display formatting, locale separators, or currency suffixes","Trim whitespace and strip annotations before parsing user- or config-sourced strings","Prefer deserialize_decimal + price_from_decimal over string parsing when the value arrives as JSON numeric data","Pin the expected wire format with a unit test on the parser"],"tags":["rust","parsing","decimal","price","format"],"backgroundTag":"invalid-argument-format","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"}