nautechsystems/nautilus_trader · error
Invalid step in bar_type.spec.step: {step} for aggregation={
Error message
Invalid step in bar_type.spec.step: {step} for aggregation={aggregation}. step must not be {subunits}. Use higher aggregation unit instead. What it means
When allow_equal is false, validate_periodic_step rejects a step exactly equal to the unit's subunit count, because such a bar is better expressed with the next higher aggregation unit (e.g. a 60-second step should be a 1-minute bar).
Source
Thrown at crates/model/src/data/bar.rs:533
try_time_interval(step, aggregation).map(|_| ())
}
fn validate_periodic_step(
step: usize,
aggregation: BarAggregation,
subunits: usize,
allow_equal: bool,
) -> anyhow::Result<()> {
if !subunits.is_multiple_of(step) {
anyhow::bail!(
"Invalid step in bar_type.spec.step: {step} for aggregation={aggregation}. \
step must evenly divide {subunits} (so it is periodic).",
);
}
if !allow_equal && subunits == step {
anyhow::bail!(
"Invalid step in bar_type.spec.step: {step} for aggregation={aggregation}. \
step must not be {subunits}. Use higher aggregation unit instead.",
);
}
Ok(())
}
/// Creates a new [`BarSpecification`] instance.
///
/// # Panics
///
/// Panics if `step` is not positive (> 0), if `step` is not valid for
/// a fixed-subunit time aggregation, or if a time-aggregated `step`
/// overflows the representable duration or nanosecond interval.
#[must_use]
pub fn new(step: usize, aggregation: BarAggregation, price_type: PriceType) -> Self {
Self::new_checked(step, aggregation, price_type).expect(FAILED)View on GitHub (pinned to 18893faf8b)
Solutions
- Replace the step with the next aggregation unit (60s -> 1 Minute step 1)
- If equality is truly intended, validate with allow_equal=true
- Normalize step/aggregation pairs in config loading
Example fix
// before BarTypeSpec::new(Second, 60)?; // bails: equals subunits // after BarTypeSpec::new(Minute, 1)?;
Defensive patterns
Strategy: validation
Validate before calling
if step == subunits && !allow_equal {
// promote to next aggregation unit: e.g. Second(60) -> Minute(1)
}
validate_periodic_step(step, aggregation, subunits, false)?; Try / catch
match validate_periodic_step(step, aggregation, subunits, false) {
Err(e) if e.to_string().contains("Use higher aggregation unit") => { /* rebuild spec with higher unit */ }
other => other?,
} Prevention
- Normalize 60s->1m, 60m->1h, 24h->1d in config loading
- Use the smallest sensible unit only for steps below the unit boundary
- Document that equal steps are disallowed unless allow_equal=true
When it happens
Trigger: Specifying a step equal to the parent unit (60-second step in Second aggregation, 60-minute step in Minute aggregation) while allow_equal=false.
Common situations: Users writing bar specs in the lower unit out of habit ("60s" instead of "1m"); code generators that normalize durations downward; config migrations.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- Invalid step in bar_type.spec.step: {step} for aggregation={
- Derive only supports minute intervals 1, 5, 15, 30 (use HOUR
- Derive only supports hour intervals 1, 4, 8
- Derive only supports 1 DAY interval bars
- Only EXTERNAL aggregation is supported
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/eacbe017b679fe42.
Report an issue: GitHub.