nautechsystems/nautilus_trader · error
Error converting enum
Error message
Error converting enum
What it means
bar_specification_new is a C FFI constructor that receives the bar aggregation as a raw u8 discriminator and converts it with BarAggregation::from_repr(...).expect("Error converting enum"). If the u8 does not map to a valid BarAggregation variant, the expect panics. The library throws it because the FFI boundary cannot return a Result and treats an unknown discriminant as a caller contract violation.
Source
Thrown at crates/model/src/ffi/data/bar.rs:45
use crate::{
data::bar::{Bar, BarSpecification, BarType},
enums::{AggregationSource, BarAggregation, PriceType},
identifiers::InstrumentId,
types::{Price, Quantity},
};
/// # Panics
///
/// Panics if `aggregation` or `price_type` do not correspond to valid enum variants.
#[unsafe(no_mangle)]
pub extern "C" fn bar_specification_new(
step: usize,
aggregation: u8,
price_type: u8,
) -> BarSpecification {
let aggregation =
BarAggregation::from_repr(aggregation as usize).expect("Error converting enum");
let price_type = PriceType::from_repr(price_type as usize).expect("Error converting enum");
BarSpecification::new(step, aggregation, price_type)
}
/// Returns a [`BarSpecification`] as a C string pointer.
#[unsafe(no_mangle)]
pub extern "C" fn bar_specification_to_cstr(bar_spec: &BarSpecification) -> *const c_char {
str_to_cstr(&bar_spec.to_string())
}
#[unsafe(no_mangle)]
pub extern "C" fn bar_specification_hash(bar_spec: &BarSpecification) -> u64 {
let mut h = DefaultHasher::new();
bar_spec.hash(&mut h);
h.finish()
}
#[unsafe(no_mangle)]View on GitHub (pinned to 18893faf8b)
Solutions
- Pass aggregation values only from the bindings' own BarAggregation enum (e.g. nautilus_model.core.data enums), not hand-picked integers.
- Rebuild/reinstall the package so the Cython bindings and Rust extension are from the same version.
- Validate the configured aggregation string (e.g. "MINUTE", "TICK") against the enum before lowering to a byte.
- If writing raw FFI, add a caller-side check that the byte is in the documented repr range before invoking.
Example fix
// before (Python FFI call) bar_specification_new(1, 7, 1) # 7 is not a valid BarAggregation // after bar_specification_new(1, int(BarAggregation.MINUTE), int(PriceType.LAST))
Defensive patterns
Strategy: validation
Validate before calling
# Python caller
VALID_AGGREGATIONS = set(range(1, len(BarAggregation) + 1))
assert aggregation in VALID_AGGREGATIONS, f"bad aggregation repr {aggregation}" Type guard
def is_valid_aggregation(v: int) -> bool:
try:
BarAggregation(v)
return True
except ValueError:
return False Prevention
- Always pass enum members, never raw integers, across the FFI boundary.
- Keep Rust crate and Cython bindings versions in lockstep.
- Validate config strings against the enum before lowering to a byte.
When it happens
Trigger: Calling the exported bar_specification_new from Python/FFI with an aggregation byte outside the valid BarAggregation repr range (e.g. 0, 255, or an int from a stale/foreign enum table).
Common situations: Version mismatch between the Cython-generated bindings and the compiled Rust extension (enum discriminants shifted), hand-rolled ctypes/cffi calls passing the wrong constant, or a script building specs from unvalidated config values.
Understand the failure class
Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.
Related errors
- Invalid scientific notation exponent '{exponent}': must be a
- Invalid NodeState value
- invalid `AggressorSide` enum string value, was '{value}'
- invalid `AssetClass` enum string value, was '{value}'
- invalid `InstrumentClass` enum string value, was '{value}'
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/ea9c821700d9350a.
Report an issue: GitHub.