nautechsystems/nautilus_trader · error

Invalid scientific notation exponent '{exponent}': must be a

Error message

Invalid scientific notation exponent '{exponent}': must be a valid number

What it means

`precision_from_v1_str` is a temporary legacy parser that infers a price-precision u8 from v1 source text. When the text uses scientific notation (`e-`), the exponent substring must parse as a number; if it contains non-digit characters the parser panics with this message. It protects against silently mapping malformed exponents (like `1e-abc`) to a wrong precision. The panic is converted to an abort via `abort_on_panic` in the FFI entry `precision_from_cstr`.

Source

Thrown at crates/core/src/ffi/parsing.rs:214

        let exponent = value
            .split("e-")
            .nth(1)
            .expect("Invalid scientific notation format: missing exponent after 'e-'");

        if let Ok(exponent) = exponent.parse::<u64>() {
            return u8::try_from(exponent).unwrap_or(u8::MAX);
        }

        assert!(
            !exponent.is_empty(),
            "Invalid scientific notation format: missing exponent after 'e-'"
        );

        if exponent.chars().all(|c| c.is_ascii_digit()) {
            return u8::MAX;
        }

        panic!("Invalid scientific notation exponent '{exponent}': must be a valid number");
    }

    value.split_once('.').map_or(0, |(_, decimal)| {
        u8::try_from(decimal.len()).unwrap_or(u8::MAX)
    })
}

/// Return a `bool` value from the given `u8`.
#[must_use]
pub const fn u8_as_bool(value: u8) -> bool {
    value != 0
}

#[cfg(test)]
mod tests {
    use std::ffi::CString;

    use rstest::rstest;

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Correct the source string so the exponent is all digits (e.g. `1.5e-6`).
  2. Sanitize/validate numeric strings on the caller side before crossing the FFI boundary.
  3. Convert the value to plain decimal notation instead of scientific notation when generating v1 data.
  4. Pre-validate with an equivalent parser, since `abort_on_panic` turns the panic into a process abort.

Example fix

// before (data)
price_increment = "1e-5x"
// after
price_increment = "1e-5"  // or "0.00001"
Defensive patterns

Strategy: validation

Validate before calling

// Validate before crossing the FFI boundary
fn is_v1_numeric(s: &str) -> bool {
    let s = s.trim().to_ascii_lowercase();
    if let Some(idx) = s.find("e-") {
        let exp = &s[idx + 2..];
        return !exp.is_empty() && exp.chars().all(|c| c.is_ascii_digit());
    }
    true
}

Type guard

fn valid_exponent(s: &str) -> bool {
    s.split_once("e-").map_or(true, |(_, exp)| !exp.is_empty() && exp.chars().all(|c| c.is_ascii_digit()))
}

Prevention

When it happens

Trigger: Passing a C string price/increment like `"1.5e-XY"` or `"2e-1_0"` (exponent with non-digit chars) to `precision_from_cstr`; only strings containing `e-` with a garbage exponent reach the panic — plain decimals or missing/empty exponents panic earlier with different messages.

Common situations: Feeding locale-mangled numbers (thousands separators, letters) from legacy v1 config or CSV data into the FFI boundary; hand-written adapter configs where an increment was typed incorrectly; truncation of a number string mid-exponent.

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


AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08). Data as JSON: /api/errors/be90f1b016f053a4. Report an issue: GitHub.