{"record":{"id":"eacbe017b679fe42","repo":"nautechsystems/nautilus_trader","slug":"invalid-step-in-bar-type-spec-step-step-for-agg-eacbe0","errorCode":null,"errorMessage":"Invalid step in bar_type.spec.step: {step} for aggregation={aggregation}. step must not be {subunits}. Use higher aggregation unit instead.","messagePattern":"Invalid step in bar_type\\.spec\\.step: (.+?) for aggregation=(.+?)\\. step must not be (.+?)\\. Use higher aggregation unit instead\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/model/src/data/bar.rs","lineNumber":533,"sourceCode":"\n        try_time_interval(step, aggregation).map(|_| ())\n    }\n\n    fn validate_periodic_step(\n        step: usize,\n        aggregation: BarAggregation,\n        subunits: usize,\n        allow_equal: bool,\n    ) -> anyhow::Result<()> {\n        if !subunits.is_multiple_of(step) {\n            anyhow::bail!(\n                \"Invalid step in bar_type.spec.step: {step} for aggregation={aggregation}. \\\n                 step must evenly divide {subunits} (so it is periodic).\",\n            );\n        }\n\n        if !allow_equal && subunits == step {\n            anyhow::bail!(\n                \"Invalid step in bar_type.spec.step: {step} for aggregation={aggregation}. \\\n                 step must not be {subunits}. Use higher aggregation unit instead.\",\n            );\n        }\n\n        Ok(())\n    }\n\n    /// Creates a new [`BarSpecification`] instance.\n    ///\n    /// # Panics\n    ///\n    /// Panics if `step` is not positive (> 0), if `step` is not valid for\n    /// a fixed-subunit time aggregation, or if a time-aggregated `step`\n    /// overflows the representable duration or nanosecond interval.\n    #[must_use]\n    pub fn new(step: usize, aggregation: BarAggregation, price_type: PriceType) -> Self {\n        Self::new_checked(step, aggregation, price_type).expect(FAILED)","sourceCodeStart":515,"sourceCodeEnd":551,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/model/src/data/bar.rs#L515-L551","documentation":"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).","triggerScenarios":"Specifying a step equal to the parent unit (60-second step in Second aggregation, 60-minute step in Minute aggregation) while allow_equal=false.","commonSituations":"Users writing bar specs in the lower unit out of habit (\"60s\" instead of \"1m\"); code generators that normalize durations downward; config migrations.","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"],"exampleFix":"// before\nBarTypeSpec::new(Second, 60)?; // bails: equals subunits\n// after\nBarTypeSpec::new(Minute, 1)?;","handlingStrategy":"validation","validationCode":"if step == subunits && !allow_equal {\n    // promote to next aggregation unit: e.g. Second(60) -> Minute(1)\n}\nvalidate_periodic_step(step, aggregation, subunits, false)?;","typeGuard":null,"tryCatchPattern":"match validate_periodic_step(step, aggregation, subunits, false) {\n    Err(e) if e.to_string().contains(\"Use higher aggregation unit\") => { /* rebuild spec with higher unit */ }\n    other => other?,\n}","preventionTips":["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"],"tags":["rust","bars","aggregation","step","validation"],"backgroundTag":"invalid-argument-value","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"}