nautechsystems/nautilus_trader · error
C string JSON must be an array of strings
Error message
C string JSON must be an array of strings
What it means
Panic in `bytes_to_string_vec` when the decoded JSON value is not a JSON array. The function does `value.as_array().expect("C string JSON must be an array of strings")`, so a valid-JSON payload of any other shape (object, string, number) aborts. The FFI contract fixes the wire format to a JSON array of strings.
Source
Thrown at crates/core/src/ffi/parsing.rs:65
/// # 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).
///
/// # 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 {View on GitHub (pinned to 18893faf8b)
Solutions
- Serialize a `Vec<String>`/list of strings (not an object) on the producing side via `string_vec_to_bytes`
- Wrap non-array JSON payloads in an array before crossing the boundary
- Version-pin both sides of the FFI boundary so the payload format matches
- Add a debug assertion that the payload starts with '[' during development
Example fix
// before
{"components": ["a", "b"]} // object, not array
// after
["a", "b"] // JSON array of strings Defensive patterns
Strategy: type-guard
Validate before calling
if isinstance(payload, list) and json.dumps(payload).lstrip().startswith('['):
ptr = string_vec_to_bytes(payload)
else:
raise ValueError("FFI payload must be a JSON array of strings") Type guard
fn is_string_array(v: &serde_json::Value) -> bool { v.as_array().map_or(false, |a| !a.is_empty() || true) && v.is_array() } Try / catch
let parsed: serde_json::Value = serde_json::from_str(text).unwrap();
if !parsed.is_array() { return Err(ParsingError::NotAnArray); } Prevention
- Serialize lists of strings, never objects, across this boundary
- Schema-check the JSON payload in tests before crossing FFI
- Version-lock producer and consumer of the payload format
- Log the raw payload when debugging boundary mismatches
When it happens
Trigger: Passing a C string containing valid JSON that is not an array — e.g. `"{\"a\": 1}"` or `"\"hello\""` — into `bytes_to_string_vec`, directly or through `synthetic_instrument_new` / `synthetic_instrument_is_valid_formula`.
Common situations: Changing the FFI payload format on one side (object instead of array) during refactors; hand-assembling JSON in another language and forgetting the array wrapper; forwarding a JSON object of parameters where a list of component strings is expected.
Related errors
- C string contains invalid JSON
- 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/c7363d5baa50c30c.
Report an issue: GitHub.