nautechsystems/nautilus_trader · critical
invalid `AggressorSide` enum string value, was '{value}'
Error message
invalid `AggressorSide` enum string value, was '{value}' What it means
This panic comes from `aggressor_side_from_cstr`, a C FFI wrapper that converts a C string into the Rust `AggressorSide` enum. It fires when the input string does not match any `AggressorSide` variant when parsed via `FromStr`. Because a Rust panic crossing the FFI boundary would be undefined behavior, the wrapper runs inside `abort_on_panic`, so invalid input aborts the process rather than returning an error. Only exact canonical variant strings (as produced by `aggressor_side_to_cstr`) are accepted.
Source
Thrown at crates/model/src/ffi/enums.rs:342
pub extern "C" fn aggressor_side_to_cstr(value: AggressorSide) -> *const c_char {
str_to_cstr(value.as_ref())
}
/// Returns an enum from a C string.
///
/// # Safety
///
/// Assumes `ptr` is a valid C string pointer.
///
/// # Panics
///
/// Panics if the C string does not correspond to a valid `AggressorSide` variant.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn aggressor_side_from_cstr(ptr: *const c_char) -> AggressorSide {
abort_on_panic(|| {
let value = unsafe { cstr_as_str(ptr) };
AggressorSide::from_str(value)
.unwrap_or_else(|_| panic!("invalid `AggressorSide` enum string value, was '{value}'"))
})
}
#[unsafe(no_mangle)]
pub extern "C" fn asset_class_to_cstr(value: AssetClass) -> *const c_char {
str_to_cstr(value.as_ref())
}
/// Returns an enum from a C string.
///
/// # Safety
///
/// Assumes `ptr` is a valid C string pointer.
///
/// # Panics
///
/// Panics if the C string does not correspond to a valid `AssetClass` variant.
#[unsafe(no_mangle)]View on GitHub (pinned to 18893faf8b)
Solutions
- Log the exact failing string and compare it character-by-character with the canonical `AggressorSide` variant strings (get a reference via `aggressor_side_to_cstr` on a valid enum value).
- Derive strings from the library's `AggressorSide` enum via `aggressor_side_to_cstr` instead of hard-coding literals.
- Trim whitespace and fix casing so the string matches the enum's FromStr spelling exactly.
- If a version upgrade introduced this, diff your hard-coded strings against the current enum definition in the model crate.
- Validate the string against the accepted variant set before the FFI call, since failure aborts the process.
Example fix
// before (Python caller passing a guessed value) side = "buy" value = aggressor_side_from_cstr(side.encode()) // after side = "BUY" # canonical spelling; or derive via aggressor_side_to_cstr(AggressorSide.BUY) value = aggressor_side_from_cstr(side.encode())
Defensive patterns
Strategy: validation
Validate before calling
VALID_AGGRESSOR_SIDES = {"NO_AGGRESSOR_SIDE", "BUY", "SELL"} # verify against enum definition
assert side_str in VALID_AGGRESSOR_SIDES, f"bad AggressorSide: {side_str!r}"
value = aggressor_side_from_cstr(side_str.encode()) Type guard
def is_valid_aggressor_side(s: str) -> bool:
return s in {"NO_AGGRESSOR_SIDE", "BUY", "SELL"} # keep in sync with the enum Prevention
- Always derive strings via the library's to_cstr/enum serialization instead of hard-coding literals.
- Normalize case and strip whitespace at every FFI boundary before passing enum strings.
- Keep a pre-call whitelist of accepted variant strings for each enum you pass across the FFI.
- After upgrading the library, diff enum serializations against your hard-coded strings.
- Remember invalid input aborts the process (abort_on_panic), so validate eagerly.
When it happens
Trigger: Calling `aggressor_side_from_cstr(ptr)` from C/Python/Cython with a string that is not a valid `AggressorSide` serialization — e.g. lowercase 'buy'/'sell' instead of the canonical variant spelling, an empty string, whitespace-padded input, or a value whose spelling changed between library versions.
Common situations: Hand-writing enum strings in strategy configs instead of round-tripping through the library's to_cstr serialization; passing a Python str without case normalization; upgrading NautilusTrader where an enum variant was renamed; typos in adapter code.
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 `AssetClass` enum string value, was '{value}'
- invalid `InstrumentClass` enum string value, was '{value}'
- invalid `BarAggregation` enum string value, was '{value}'
- invalid `BookAction` enum string value, was '{value}'
- invalid `BookType` enum string value, was '{value}'
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/d799616d08fe12a3.
Report an issue: GitHub.