nautechsystems/nautilus_trader · error
C string JSON array must contain only strings
Error message
C string JSON array must contain only strings
What it means
Panic in `bytes_to_string_vec` when the JSON array contains non-string elements. Each element goes through `value.as_str().expect("C string JSON array must contain only strings")`, so numbers, nulls, booleans, or nested arrays inside the array cause a panic. The FFI wire format is strictly `Vec<String>` encoded as JSON.
Source
Thrown at crates/core/src/ffi/parsing.rs:71
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).
///
/// # Panics
///
/// Panics if JSON serialization fails or if the generated string contains interior null bytes.
#[must_use]
pub fn string_vec_to_bytes(strings: &[String]) -> *const c_char {
let json_string = serde_json::to_string(strings).expect("Failed to serialize strings to JSON");
let c_string = CString::new(json_string).expect("JSON string contains interior null bytes");
c_string.into_raw()
}
View on GitHub (pinned to 18893faf8b)
Solutions
- Coerce all elements to strings before serializing (e.g. `[str(x) for x in items]` in Python)
- Filter out or stringify None/null entries prior to `string_vec_to_bytes`
- Validate the JSON with a schema (`array of string`) at the boundary in debug builds
- Ensure the producer language's list is homogeneous before crossing FFI
Example fix
# before (Python side) components = ["ema", 10, None] # after components = [str(x) for x in components if x is not None]
Defensive patterns
Strategy: validation
Validate before calling
if not all(isinstance(x, str) for x in components):
components = [str(x) for x in components if x is not None] Type guard
fn all_strings(items: &[serde_json::Value]) -> bool { items.iter().all(|v| v.is_string()) } Try / catch
let vals: Vec<serde_json::Value> = serde_json::from_str(text)?;
if !vals.iter().all(|v| v.is_string()) { return Err(ParsingError::NonStringElement); } Prevention
- Coerce heterogeneous lists to strings before serialization
- Filter null/None entries at the source
- Use typed lists (list[str]) in the calling language
- Validate with a JSON schema (array of strings) in tests
When it happens
Trigger: Passing a C string holding e.g. `["a", 1, null]` into `bytes_to_string_vec`, or through the synthetic-instrument FFI entry points that consume component lists.
Common situations: Serializing a mixed-type list (e.g. Python `list` containing ints/None) on the calling-language side; loose JSON construction in scripts; dynamic data where a component is accidentally `None` and serialized as null.
Understand the failure class
Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.
Related errors
- C string contains invalid JSON
- C string JSON must be an array of strings
- Failed to serialize strings to JSON
- JSON string contains interior null bytes
- Actor type mismatch for '{id}': expected {expected_type:?},
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/1cd832fbd5c19819.
Report an issue: GitHub.