{"record":{"id":"d799616d08fe12a3","repo":"nautechsystems/nautilus_trader","slug":"invalid-aggressorside-enum-string-value-was-v","errorCode":null,"errorMessage":"invalid `AggressorSide` enum string value, was '{value}'","messagePattern":"invalid `AggressorSide` enum string value, was '(.+?)'","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"crates/model/src/ffi/enums.rs","lineNumber":342,"sourceCode":"pub extern \"C\" fn aggressor_side_to_cstr(value: AggressorSide) -> *const c_char {\n    str_to_cstr(value.as_ref())\n}\n\n/// Returns an enum from a C string.\n///\n/// # Safety\n///\n/// Assumes `ptr` is a valid C string pointer.\n///\n/// # Panics\n///\n/// Panics if the C string does not correspond to a valid `AggressorSide` variant.\n#[unsafe(no_mangle)]\npub unsafe extern \"C\" fn aggressor_side_from_cstr(ptr: *const c_char) -> AggressorSide {\n    abort_on_panic(|| {\n        let value = unsafe { cstr_as_str(ptr) };\n        AggressorSide::from_str(value)\n            .unwrap_or_else(|_| panic!(\"invalid `AggressorSide` enum string value, was '{value}'\"))\n    })\n}\n\n#[unsafe(no_mangle)]\npub extern \"C\" fn asset_class_to_cstr(value: AssetClass) -> *const c_char {\n    str_to_cstr(value.as_ref())\n}\n\n/// Returns an enum from a C string.\n///\n/// # Safety\n///\n/// Assumes `ptr` is a valid C string pointer.\n///\n/// # Panics\n///\n/// Panics if the C string does not correspond to a valid `AssetClass` variant.\n#[unsafe(no_mangle)]","sourceCodeStart":324,"sourceCodeEnd":360,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/model/src/ffi/enums.rs#L324-L360","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before (Python caller passing a guessed value)\nside = \"buy\"\nvalue = aggressor_side_from_cstr(side.encode())\n// after\nside = \"BUY\"  # canonical spelling; or derive via aggressor_side_to_cstr(AggressorSide.BUY)\nvalue = aggressor_side_from_cstr(side.encode())","handlingStrategy":"validation","validationCode":"VALID_AGGRESSOR_SIDES = {\"NO_AGGRESSOR_SIDE\", \"BUY\", \"SELL\"}  # verify against enum definition\nassert side_str in VALID_AGGRESSOR_SIDES, f\"bad AggressorSide: {side_str!r}\"\nvalue = aggressor_side_from_cstr(side_str.encode())","typeGuard":"def is_valid_aggressor_side(s: str) -> bool:\n    return s in {\"NO_AGGRESSOR_SIDE\", \"BUY\", \"SELL\"}  # keep in sync with the enum","tryCatchPattern":null,"preventionTips":["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."],"tags":["ffi","rust","panic","enum-parsing","process-abort"],"backgroundTag":"invalid-enum-value","analyzedSha":"18893faf8b356be3320add8de2f861b0b647cf06","analyzedAt":"2026-09-08T20:49:34.690Z","contentChangedAt":"2026-09-08T20:49:34.690Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}