nautechsystems/nautilus_trader · error

JSON string contains interior null bytes

Error message

JSON string contains interior null bytes

What it means

Panic in `string_vec_to_bytes`: after serializing to JSON, `CString::new(json_string).expect("JSON string contains interior null bytes")` aborts if the JSON text contains an interior NUL byte. Since CString cannot represent interior nulls, the library treats such output as a contract violation. For normal string contents serde_json escapes NULs as \u0000, so this is also effectively unreachable for plain strings.

Source

Thrown at crates/core/src/ffi/parsing.rs:85

    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()
}

/// Convert a C bytes pointer into an owned `Option<HashMap<String, Value>>`.
///
/// # Safety
///
/// Assumes `ptr` is a valid C string pointer.
///
/// # Panics
///
/// Panics if `ptr` is not null but contains invalid UTF-8 or JSON.
#[must_use]
pub unsafe fn optional_bytes_to_json(ptr: *const c_char) -> Option<HashMap<String, Value>> {
    // SAFETY: A non-null pointer is valid under the caller's contract
    unsafe { optional_json_from_cstr(ptr) }
}

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Inspect the input strings for raw NUL bytes and strip them at the source if feeding non-standard data
  2. Do not post-process/replace within the serialized JSON before conversion
  3. Use the standard serde_json version; rebuild if a patched dependency is present
  4. If reproducible with plain strings, report it — the expected behavior is escaped \u0000, no panic

Example fix

// before
let s = String::from_utf8(vec![b'a', 0, b'b']).unwrap(); // raw interior NUL handled ad-hoc
// after
let cleaned: String = s.chars().filter(|&c| c != '\0').collect();
let ptr = string_vec_to_bytes(&[cleaned]);
Defensive patterns

Strategy: validation

Validate before calling

assert!(!json_string.contains('\0'), "JSON payload must not contain raw NUL bytes");

Try / catch

let result = std::panic::catch_unwind(|| string_vec_to_bytes(strings));
if result.is_err() { eprintln!("interior NUL in serialized JSON"); }

Prevention

When it happens

Trigger: Calling `string_vec_to_bytes` when the serialized JSON unexpectedly contains a raw interior null byte — realistically only via non-standard serialization output or corrupted string data, not ordinary `Vec<String>` content.

Common situations: Very rare: custom string types or patched serializers emitting raw NULs; post-processing the JSON string before passing it in; memory corruption. Ordinary usage (strings containing '\0') is safe because serde_json escapes them.

Understand the failure class

Background: "JSON serialization failed", "not JSON serializable", "Failed to serialize": why JSON marshaling errors happen and how to fix them — this error's family across 46 libraries.

Related errors


AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08). Data as JSON: /api/errors/972d16b35a755d48. Report an issue: GitHub.