{"record":{"id":"8e2b0c1c58c19b3e","repo":"nautechsystems/nautilus_trader","slug":"c-string-contains-invalid-json","errorCode":null,"errorMessage":"C string contains invalid JSON","messagePattern":"C string contains invalid JSON","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/core/src/ffi/parsing.rs","lineNumber":61,"sourceCode":"/// # Safety\n///\n/// Assumes `ptr` is a valid C string pointer.\n///\n/// # Panics\n///\n/// Panics if `ptr` is null, contains invalid UTF-8/JSON, or the JSON value\n/// is not an array of strings.\n#[must_use]\npub unsafe fn bytes_to_string_vec(ptr: *const c_char) -> Vec<String> {\n    assert!(!ptr.is_null(), \"`ptr` was NULL\");\n\n    // SAFETY: Caller guarantees ptr is valid per function contract\n    let c_str = unsafe { CStr::from_ptr(ptr) };\n    let bytes = c_str.to_bytes();\n\n    let json_string = std::str::from_utf8(bytes).expect(\"C string contains invalid UTF-8\");\n    let value: serde_json::Value =\n        serde_json::from_str(json_string).expect(\"C string contains invalid JSON\");\n\n    let arr = value\n        .as_array()\n        .expect(\"C string JSON must be an array of strings\");\n\n    arr.iter()\n        .map(|value| {\n            value\n                .as_str()\n                .expect(\"C string JSON array must contain only strings\")\n                .to_owned()\n        })\n        .collect()\n}\n\n/// Convert a slice of `String` into a C string pointer (JSON encoded).\n///\n/// # Panics","sourceCodeStart":43,"sourceCodeEnd":79,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/core/src/ffi/parsing.rs#L43-L79","documentation":"A panic in `bytes_to_string_vec` (crates/core/src/ffi/parsing.rs): the function receives a C string pointer from the PyO3/C boundary, decodes UTF-8, then parses it as JSON with `serde_json::from_str(...).expect(\"C string contains invalid JSON\")`. If the C string is not valid JSON, the process panics. This is a boundary invariant: `string_vec_to_bytes` always emits JSON, so anything else indicates corrupted or mismatched FFI data.","triggerScenarios":"Calling `bytes_to_string_vec` (directly or via `synthetic_instrument_new` / `synthetic_instrument_is_valid_formula`) with a pointer to bytes that are valid UTF-8 but not valid JSON — e.g. a bare string, a truncated buffer, or data not produced by `string_vec_to_bytes`.","commonSituations":"Hand-rolling C FFI calls that pass non-JSON payloads; memory truncation of the buffer before the terminating null; version mismatch where one side of the boundary encodes differently; tests feeding malformed input.","solutions":["Ensure the buffer comes from `string_vec_to_bytes` (JSON-encoded array of strings) and is passed unmodified","Print/decode the bytes with `std::str::from_utf8` and a JSON parser to inspect the actual payload before the call","Check for buffer truncation or double-free style bugs at the FFI boundary","In tests, use `string_vec_to_bytes` to build the input rather than crafting raw C strings"],"exampleFix":"// before\nlet ptr = CString::new(\"not json\").unwrap().into_raw();\nlet v = bytes_to_string_vec(ptr); // panics\n// after\nlet ptr = string_vec_to_bytes(&vec![\"a\".to_string(), \"b\".to_string()]);\nlet v = bytes_to_string_vec(ptr); // OK","handlingStrategy":"validation","validationCode":"let text = unsafe { CStr::from_ptr(ptr) }.to_str()?;\nserde_json::from_str::<serde_json::Value>(text)?; // validate before calling","typeGuard":"fn is_json_string_array(bytes: &[u8]) -> bool {\n    std::str::from_utf8(bytes).ok()\n        .and_then(|s| serde_json::from_str::<serde_json::Value>(s).ok())\n        .map_or(false, |v| v.is_array())\n}","tryCatchPattern":"// wrap unsafe boundary in catch_unwind and inspect payload on failure\nlet result = std::panic::catch_unwind(|| bytes_to_string_vec(ptr));\nmatch result { Ok(v) => v, Err(_) => { log_payload(ptr); fallback_vec() } }","preventionTips":["Only pass buffers produced by string_vec_to_bytes across the boundary","Round-trip test your FFI payloads (string_vec_to_bytes -> bytes_to_string_vec)","Never truncate or hand-edit JSON C strings","Keep both FFI sides on the same nautilus version"],"tags":["rust","ffi","json","panic","parsing"],"backgroundTag":"json-parse-error","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"}