PyO3/pyo3 · error

string contains nul bytes

Error message

string contains nul bytes

What it means

The hidden const helper _cstr_from_utf8_with_nul_checked builds a CStr from a &str at compile time via c_str!. CStr::from_bytes_with_nul fails if the input has interior NUL bytes or doesn't end in exactly one NUL, and const fns can only panic, so it panics with "string contains nul bytes".

Source

Thrown at pyo3-ffi/src/lib.rs:428

/// use core::ffi::CStr;
///
/// const HELLO: &CStr = pyo3_ffi::c_str!("hello");
/// static WORLD: &CStr = pyo3_ffi::c_str!("world");
/// ```
#[macro_export]
macro_rules! c_str {
    // TODO: deprecate this now MSRV is above 1.77
    ($s:expr) => {
        $crate::_cstr_from_utf8_with_nul_checked(concat!($s, "\0"))
    };
}

/// Private helper for `c_str!` macro.
#[doc(hidden)]
pub const fn _cstr_from_utf8_with_nul_checked(s: &str) -> &core::ffi::CStr {
    match core::ffi::CStr::from_bytes_with_nul(s.as_bytes()) {
        Ok(cstr) => cstr,
        Err(_) => panic!("string contains nul bytes"),
    }
}

// Macros for declaring `extern` blocks that link against libpython.
#[path = "impl_/macros.rs"]
#[macro_use]
mod macros;

pub mod compat;
mod impl_;

pub use self::abstract_::*;
#[cfg(not(RustPython))]
pub use self::bltinmodule::*;
pub use self::boolobject::*;
pub use self::bytearrayobject::*;
pub use self::bytesobject::*;
pub use self::ceval::*;

View on GitHub (pinned to ac9b6899d3)

Solutions

  1. Remove interior NUL bytes from the string literal
  2. Use a single trailing \0 only (which the macro expects)
  3. Use std::ffi::CStr::from_bytes_with_nul manually with error handling for runtime strings

Example fix

// before
let s = c_str!("foo\0bar\0");
// after
let s = c_str!("foobar\0");
Defensive patterns

Strategy: validation

Validate before calling

fn is_cstr_safe(s: &str) -> bool {
    s.as_bytes().iter().filter(|&&b| b == 0).count() == 1 && s.ends_with('\0')
}

Prevention

When it happens

Trigger: Using the c_str! macro (or calling _cstr_from_utf8_with_nul_checked) with a string literal containing an interior \0 or not properly NUL-terminated by the macro.

Common situations: Programmatically generated literals that embed embedded NULs; typos like "foo\0bar" intended as a C identifier; macro misuse with already-escaped strings.

Related errors


AI-assisted analysis of PyO3/pyo3@ac9b6899d3 (2026-09-05). Data as JSON: /api/errors/37ece03901cb7f37. Report an issue: GitHub.