PyO3/pyo3 · error · syn::Error

Python doc may not contain nul byte, found nul at position {

Error message

Python doc may not contain nul byte, found nul at position {}

What it means

When converting a Python docstring literal to a C string, pyo3's macro backend uses CString::new, which fails if the doc text contains an embedded NUL byte ('\0'). Since C strings cannot contain NUL, the macro surfaces the byte position of the offending NUL in this error.

Source

Thrown at pyo3-macros-backend/src/utils.rs:156

    if parts.is_empty() {
        None
    } else {
        Some(PythonDoc { parts })
    }
}

impl PythonDoc {
    pub fn to_cstr_stream(&self, ctx: &Ctx) -> syn::Result<TokenStream> {
        let parts = &self.parts;
        if let [StrOrExpr::Str { value, span }] = &parts[..] {
            // Simple case, a single string. We serialize as such
            return match CString::new(value.clone()) {
                Ok(null_terminated_value) => Ok(LitCStr::new(
                    &null_terminated_value,
                    span.unwrap_or_else(Span::call_site),
                )
                .into_token_stream()),
                Err(e) => Err(syn::Error::new(
                    span.unwrap_or_else(Span::call_site),
                    format!(
                        "Python doc may not contain nul byte, found nul at position {}",
                        e.nul_position()
                    ),
                )),
            };
        }
        let Ctx { pyo3_path, .. } = ctx;
        Ok(quote!(#pyo3_path::ffi::c_str!(concat!(#(#parts),*))))
    }
}

/// A plain string or an expression
#[derive(Clone)]
pub enum StrOrExpr {
    Str { value: String, span: Option<Span> },
    Expr(Expr),

View on GitHub (pinned to ac9b6899d3)

Solutions

  1. Remove the \0 (NUL) character from the doc comment
  2. Replace NUL with an escaped textual representation like "\\0" or "NULL"
  3. If docs are generated, sanitize output to strip NUL bytes

Example fix

// before
/// Splits on the separator \0
#[pyfunction]
fn split(s: &str) {}
// after
/// Splits on the separator \\0 (NUL)
#[pyfunction]
fn split(s: &str) {}
Defensive patterns

Strategy: validation

Validate before calling

// reject docstrings containing NUL before use
fn doc_ok(doc: &str) -> bool { !doc.contains('\0') }

Prevention

When it happens

Trigger: A #[pyclass]/#[pyfunction] doc comment or #[doc] attribute containing a literal NUL escape (e.g. "\0") that the macro tries to turn into a C string.

Common situations: Generated doc comments built from binary data or format strings including \0; tests using NUL characters in docstrings; copy-paste of content with invisible NUL characters.

Related errors


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