nautechsystems/nautilus_trader · error · anyhow::Error

Invalid bar spec: no aggregation suffix in '{value}'

Error message

Invalid bar spec: no aggregation suffix in '{value}'

What it means

parse_bar_spec expects the last '_' separated part to begin with a numeric step (e.g. "1m", "100ticks"). If no leading ASCII digits are found in that part, there is no aggregation step, and the function rejects the value with this error naming the original spec string.

Source

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

    }
}

/// Parses a Nautilus bar specification from the given Tardis string `value`.
///
/// 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}'"))
}

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Check the spec string printed in the error — the final '_' part must start with digits, e.g. "..._1m", "..._100ticks"
  2. Convert Nautilus-style specs ("1-MINUTE") to the Tardis expected format before parsing
  3. Ensure futures symbols with month suffixes are not routed into parse_bar_spec
  4. Validate bar specs at config load to catch the typo early

Example fix

// before
let bar = parse_bar_spec("1-MINUTE")?; // no numeric step in last part
// after: Tardis-style spec
let bar = parse_bar_spec("BTCUSD_1m")?; // step '1' + suffix 'm'
Defensive patterns

Strategy: validation

Validate before calling

fn has_numeric_step(value: &str) -> bool {
    value.rsplit('_').next()
        .map(|last| last.chars().next().map(|c| c.is_ascii_digit()).unwrap_or(false))
        .unwrap_or(false)
}

Try / catch

match parse_bar_spec(spec) {
    Ok(bar) => /* proceed */,
    Err(e) if e.to_string().contains("no aggregation suffix") => {
        log::error!("malformed bar spec '{spec}': expected '<step><suffix>', e.g. '1m'");
        return Err(e.into());
    }
    Err(e) => return Err(e.into()),
}

Prevention

When it happens

Trigger: Calling parse_bar_spec with a spec whose final segment lacks a leading number: "m" (e.g. "BTCUSD_m" with no step), "minute", "1-MINUTE" if the '_' split leaves a non-numeric tail, or a symbol accidentally used as a bar spec.

Common situations: Confusing Tardis bar spec syntax with Nautilus BarSpecification strings; a Tardis symbol suffix like "_m" (month futures) being mistaken for a bar spec; typos in subscription configuration.

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/0695e5100f90127b. Report an issue: GitHub.