nautechsystems/nautilus_trader · error
C string contains invalid JSON
Error message
C string contains invalid JSON
What it means
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.
Source
Thrown at crates/core/src/ffi/parsing.rs:61
/// # Safety
///
/// Assumes `ptr` is a valid C string pointer.
///
/// # Panics
///
/// Panics if `ptr` is null, contains invalid UTF-8/JSON, or the JSON value
/// is not an array of strings.
#[must_use]
pub unsafe fn bytes_to_string_vec(ptr: *const c_char) -> Vec<String> {
assert!(!ptr.is_null(), "`ptr` was NULL");
// SAFETY: Caller guarantees ptr is valid per function contract
let c_str = unsafe { CStr::from_ptr(ptr) };
let bytes = c_str.to_bytes();
let json_string = std::str::from_utf8(bytes).expect("C string contains invalid UTF-8");
let value: serde_json::Value =
serde_json::from_str(json_string).expect("C string contains invalid JSON");
let arr = value
.as_array()
.expect("C string JSON must be an array of strings");
arr.iter()
.map(|value| {
value
.as_str()
.expect("C string JSON array must contain only strings")
.to_owned()
})
.collect()
}
/// Convert a slice of `String` into a C string pointer (JSON encoded).
///
/// # PanicsView on GitHub (pinned to 18893faf8b)
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
Example fix
// before
let ptr = CString::new("not json").unwrap().into_raw();
let v = bytes_to_string_vec(ptr); // panics
// after
let ptr = string_vec_to_bytes(&vec!["a".to_string(), "b".to_string()]);
let v = bytes_to_string_vec(ptr); // OK Defensive patterns
Strategy: validation
Validate before calling
let text = unsafe { CStr::from_ptr(ptr) }.to_str()?;
serde_json::from_str::<serde_json::Value>(text)?; // validate before calling Type guard
fn is_json_string_array(bytes: &[u8]) -> bool {
std::str::from_utf8(bytes).ok()
.and_then(|s| serde_json::from_str::<serde_json::Value>(s).ok())
.map_or(false, |v| v.is_array())
} Try / catch
// wrap unsafe boundary in catch_unwind and inspect payload on failure
let result = std::panic::catch_unwind(|| bytes_to_string_vec(ptr));
match result { Ok(v) => v, Err(_) => { log_payload(ptr); fallback_vec() } } Prevention
- 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
When it happens
Trigger: 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`.
Common situations: 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.
Understand the failure class
Background: JSON parse error: "Unexpected token" / "not valid JSON" / "failed to parse" — what JSON parsers are really complaining about — this error's family across 45 libraries.
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- C string JSON must be an array of strings
- Invalid scientific notation exponent '{exponent}': must be a
- C string JSON array must contain only strings
- Failed to serialize strings to JSON
- JSON string contains interior null bytes
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/8e2b0c1c58c19b3e.
Report an issue: GitHub.