nautechsystems/nautilus_trader · error
invalid bar step: {e}
Error message
invalid bar step: {e} What it means
`add_bar` converts the bar spec's step (a u32/nonzero) into an i32 for the Postgres `step` column. If the step exceeds `i32::MAX` (or the conversion otherwise fails) this error is returned. It guards against integer overflow when binding the parameter.
Source
Thrown at crates/infrastructure/src/sql/queries.rs:1350
.map_err(|e| anyhow::anyhow!("Failed to load quotes: {e}"))
}
/// Inserts a `Bar` entry via the provided `pool`.
///
/// # Errors
///
/// Returns an error if the SQL INSERT operation fails.
pub async fn add_bar(pool: &PgPool, bar: &Bar) -> anyhow::Result<()> {
if bar.bar_type.is_composite() {
anyhow::bail!(
"Cannot persist bar with composite bar type {}: the bar table stores only \
the standard form; standardize the bar type before persisting",
bar.bar_type,
);
}
let bar_step = i32::try_from(bar.bar_type.spec().step.get())
.map_err(|e| anyhow::anyhow!("invalid bar step: {e}"))?;
sqlx::query(r#"
INSERT INTO "bar" (
instrument_id, step, bar_aggregation, price_type, aggregation_source, open, high, low, close, volume, ts_event, ts_init, created_at, updated_at
) VALUES (
$1, $2, $3::bar_aggregation, $4::price_type, $5::aggregation_source, $6, $7, $8, $9, $10, $11, $12, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP
)
ON CONFLICT (id)
DO UPDATE
SET
instrument_id = $1, step = $2, bar_aggregation = $3::bar_aggregation, price_type = $4::price_type, aggregation_source = $5::aggregation_source,
open = $6, high = $7, low = $8, close = $9, volume = $10, ts_event = $11, ts_init = $12, updated_at = CURRENT_TIMESTAMP
"#)
.bind(bar.bar_type.instrument_id().to_string())
.bind(bar_step)
.bind(BarAggregationPg(bar.bar_type.spec().aggregation))
.bind(PriceTypePg(bar.bar_type.spec().price_type))
.bind(AggregationSourcePg(bar.bar_type.aggregation_source()))View on GitHub (pinned to 18893faf8b)
Solutions
- Validate the bar spec step fits in i32 (1..=2147483647) before constructing/persisting the bar
- Clamp or reject oversized steps at config load time
- Check the wrapped TryFromIntError to confirm it is an out-of-range step
Example fix
// before sql_cache.add_bar(&pool, &bar).await?; // after assert!(bar.bar_type.spec().step.get() <= i32::MAX as u64, "bar step too large"); sql_cache.add_bar(&pool, &bar).await?;
Defensive patterns
Strategy: validation
Validate before calling
let step = bar.bar_type.spec().step.get();
if step == 0 || step > i32::MAX as u64 {
return Err(anyhow::anyhow!("bar step {step} out of i32 range"));
} Type guard
fn bar_step_fits(step: u64) -> bool { step >= 1 && step <= i32::MAX as u64 } Try / catch
if let Err(e) = add_bar(&pool, &bar).await {
if e.to_string().contains("invalid bar step") { /* reject or fix bar spec */ }
return Err(e);
} Prevention
- Validate bar aggregation steps come from a bounded, sane range at config load
- Never build bar specs directly from raw external integers
- Test config parsing rejects absurd step values
When it happens
Trigger: Calling `add_bar(pool, &bar)` with a bar type whose `spec().step.get()` is larger than 2147483647 — practically only from programmatically constructed bar specs with absurd step values.
Common situations: Constructing BarAggregation specs from unvalidated config or external input where the step is an arbitrary u64/usize; buggy aggregation code producing huge steps.
Understand the failure class
Background: "value must be between 0 and 1" / "out of range" / "must not be negative" errors: fixing range-validation failures across open-source libraries — this error's family across 42 libraries.
Related errors
- Unsupported bar specification for AX: {step}-{:?}
- Deribit does not support resolution '{resolution}'. Supporte
- 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
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/b06e714a23b9e417.
Report an issue: GitHub.