nautechsystems/nautilus_trader · error · anyhow::Error

Invalid step in bar spec '{value}': {e}

Error message

Invalid step in bar spec '{value}': {e}

What it means

After extracting the leading digit run from the last part of a bar spec, parse_bar_spec parses it as usize. If that parse fails (e.g. a number too large for usize, or digits interleaved with later characters) the error wraps the std ParseIntError with the offending spec value.

Source

Thrown at crates/adapters/tardis/src/common/parse.rs:337

/// The [`PriceType`] is always `LAST` for Tardis trade bars.
///
/// # Errors
///
/// Returns an error if the specification format is invalid or if the aggregation suffix is unsupported.
pub fn parse_bar_spec(value: &str) -> anyhow::Result<BarSpecification> {
    let parts: Vec<&str> = value.split('_').collect();
    let last_part = parts
        .last()
        .ok_or_else(|| anyhow::anyhow!("Invalid bar spec: empty string"))?;
    let split_idx = last_part
        .chars()
        .position(|c| !c.is_ascii_digit())
        .ok_or_else(|| anyhow::anyhow!("Invalid bar spec: no aggregation suffix in '{value}'"))?;

    let (step_str, suffix) = last_part.split_at(split_idx);
    let step: usize = step_str
        .parse()
        .map_err(|e| anyhow::anyhow!("Invalid step in bar spec '{value}': {e}"))?;

    let aggregation = match suffix {
        "ms" => BarAggregation::Millisecond,
        "s" => BarAggregation::Second,
        "m" => BarAggregation::Minute,
        "ticks" => BarAggregation::Tick,
        "vol" => BarAggregation::Volume,
        _ => anyhow::bail!("Unsupported bar aggregation type: '{suffix}'"),
    };

    parse_canonical_bar_spec(step, aggregation)
        .with_context(|| format!("Invalid bar spec '{value}'"))
}

fn parse_canonical_bar_spec(
    step: usize,
    aggregation: BarAggregation,
) -> anyhow::Result<BarSpecification> {

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Check the spec value in the error message — the step must fit in usize and be a plain digit run
  2. Use a realistic aggregation step (1, 5, 60, 100...) in your bar spec
  3. Bound/validate the step value at config load before calling parse_bar_spec
  4. If steps come from user input, clamp to supported aggregation ranges

Example fix

// before
let bar = parse_bar_spec("99999999999999999999m")?; // usize overflow
// after: validate step first
let step: u64 = step_str.parse()?;
anyhow::ensure!(step <= 86_400, "step too large");
let bar = parse_bar_spec(&format!("{step}m"))?;
Defensive patterns

Strategy: validation

Validate before calling

fn step_in_range(value: &str) -> bool {
    value.rsplit('_').next()
        .and_then(|last| last.chars().position(|c| !c.is_ascii_digit()).map(|i| &last[..i]))
        .and_then(|s| s.parse::<u64>().ok())
        .map(|step| step > 0 && step <= 86_400)
        .unwrap_or(false)
}

Try / catch

match parse_bar_spec(spec) {
    Ok(bar) => /* proceed */,
    Err(e) if e.to_string().contains("Invalid step") => {
        log::error!("unparseable step in '{spec}'");
        return Err(e.into());
    }
    Err(e) => return Err(e.into()),
}

Prevention

When it happens

Trigger: Calling parse_bar_spec with a step that overflows usize (e.g. "99999999999999999999m") or a malformed step where parse cannot handle the extracted digit string.

Common situations: Corrupted config values with absurd aggregation steps; a hand-typed bar spec with a typo in the numeric portion; generated specs from a template with an unbounded substitution.

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/1b7d3ab6fb0a9aaa. Report an issue: GitHub.