{"record":{"id":"1fd12a87af03eb2d","repo":"PyO3/pyo3","slug":"python-doc-may-not-contain-nul-byte-found-nul-at","errorCode":null,"errorMessage":"Python doc may not contain nul byte, found nul at position {}","messagePattern":"Python doc may not contain nul byte, found nul at position (.+?)","errorType":"validation","errorClass":"syn::Error","httpStatus":null,"severity":"error","filePath":"pyo3-macros-backend/src/utils.rs","lineNumber":156,"sourceCode":"    if parts.is_empty() {\n        None\n    } else {\n        Some(PythonDoc { parts })\n    }\n}\n\nimpl PythonDoc {\n    pub fn to_cstr_stream(&self, ctx: &Ctx) -> syn::Result<TokenStream> {\n        let parts = &self.parts;\n        if let [StrOrExpr::Str { value, span }] = &parts[..] {\n            // Simple case, a single string. We serialize as such\n            return match CString::new(value.clone()) {\n                Ok(null_terminated_value) => Ok(LitCStr::new(\n                    &null_terminated_value,\n                    span.unwrap_or_else(Span::call_site),\n                )\n                .into_token_stream()),\n                Err(e) => Err(syn::Error::new(\n                    span.unwrap_or_else(Span::call_site),\n                    format!(\n                        \"Python doc may not contain nul byte, found nul at position {}\",\n                        e.nul_position()\n                    ),\n                )),\n            };\n        }\n        let Ctx { pyo3_path, .. } = ctx;\n        Ok(quote!(#pyo3_path::ffi::c_str!(concat!(#(#parts),*))))\n    }\n}\n\n/// A plain string or an expression\n#[derive(Clone)]\npub enum StrOrExpr {\n    Str { value: String, span: Option<Span> },\n    Expr(Expr),","sourceCodeStart":138,"sourceCodeEnd":174,"githubUrl":"https://github.com/PyO3/pyo3/blob/ac9b6899d348be4d54614d060dea53a645a12e36/pyo3-macros-backend/src/utils.rs#L138-L174","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Remove the \\0 (NUL) character from the doc comment","Replace NUL with an escaped textual representation like \"\\\\0\" or \"NULL\"","If docs are generated, sanitize output to strip NUL bytes"],"exampleFix":"// before\n/// Splits on the separator \\0\n#[pyfunction]\nfn split(s: &str) {}\n// after\n/// Splits on the separator \\\\0 (NUL)\n#[pyfunction]\nfn split(s: &str) {}","handlingStrategy":"validation","validationCode":"// reject docstrings containing NUL before use\nfn doc_ok(doc: &str) -> bool { !doc.contains('\\0') }","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Never put literal \\0 in doc comments","Sanitize generated docstrings for NUL bytes","Search codebase for '\\\\0' in doc attributes"],"tags":["rust","pyo3","macro","docstring"],"backgroundTag":"nul-byte-in-cstring","analyzedSha":"ac9b6899d348be4d54614d060dea53a645a12e36","analyzedAt":"2026-09-05T09:20:35.319Z","contentChangedAt":"2026-09-05T09:20:35.319Z","schemaVersion":2},"datasetVersion":"2026-09-12T12:17:11.808Z"}