{"record":{"id":"7e78f9273846fd94","repo":"PyO3/pyo3","slug":"pyobject-pointer-is-null","errorCode":null,"errorMessage":"PyObject pointer is null","messagePattern":"PyObject pointer is null","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"src/instance.rs","lineNumber":2429,"sourceCode":"    /// Casts the `Py<T>` to a concrete Python object type without checking validity.\n    ///\n    /// # Safety\n    ///\n    /// Callers must ensure that the type is valid or risk type confusion.\n    #[inline]\n    pub unsafe fn cast_bound_unchecked<'py, U>(&self, py: Python<'py>) -> &Bound<'py, U> {\n        // Safety: caller has upheld the safety contract\n        unsafe { self.bind(py).cast_unchecked() }\n    }\n}\n\n#[track_caller]\n#[cold]\nfn panic_on_null(py: Python<'_>) -> ! {\n    if let Some(err) = PyErr::take(py) {\n        err.write_unraisable(py, None);\n    }\n    panic!(\"PyObject pointer is null\");\n}\n\n#[cfg(test)]\nmod tests {\n    use super::{Bound, IntoPyObject, Py};\n    #[cfg(all(feature = \"macros\", panic = \"unwind\"))]\n    use crate::exceptions::PyValueError;\n    #[allow(unused_imports, reason = \"conditionally used\")]\n    use crate::platform::prelude::*;\n    use crate::test_utils::generate_unique_module_name;\n    #[cfg(all(feature = \"macros\", panic = \"unwind\"))]\n    use crate::test_utils::UnraisableCapture;\n    use crate::types::{dict::IntoPyDict, PyAnyMethods, PyCapsule, PyDict, PyString};\n    use crate::{ffi, Borrowed, IntoPyObjectExt, PyAny, PyResult, Python};\n    use core::ffi::CStr;\n\n    #[test]\n    fn test_call() {","sourceCodeStart":2411,"sourceCodeEnd":2447,"githubUrl":"https://github.com/PyO3/pyo3/blob/ac9b6899d348be4d54614d060dea53a645a12e36/src/instance.rs#L2411-L2447","documentation":"panic_on_null handles FFI results that return a NULL PyObject. It first checks whether Python's error indicator is set and writes it as unraisable (so the real cause isn't lost), then panics because a null pointer cannot be safely wrapped in a Py/Bound.","triggerScenarios":"Calling unsafe/PyO3 APIs that wrap a raw FFI result (e.g. Py::from_owned_ptr-style paths, constructor calls, attribute lookups) when the underlying C API returned NULL.","commonSituations":"Python exceptions during object construction or method calls surfaced through raw pointers; calling APIs during interpreter shutdown where allocation fails; misuse of unsafe Py APIs with pointers from foreign code.","solutions":["Look at the unraisable exception printed before the panic — it contains the actual Python error","Wrap raw FFI calls to check for NULL yourself before converting (Py::from_owned_ptr_or_err) and return a proper PyResult","Ensure calls happen while the interpreter is fully initialized and errors are checked between FFI calls"],"exampleFix":"// before\nlet obj = unsafe { Py::from_owned_ptr(py, ffi::PyImport_Import(...)) };\n// after\nlet obj = unsafe { Py::from_owned_ptr_or_err(py, ffi::PyImport_Import(...))? };","handlingStrategy":"try-catch","validationCode":"// check raw FFI results before converting\nlet ptr = unsafe { ffi_call() };\nif ptr.is_null() {\n    return Err(PyErr::take(py).unwrap_or_else(|| PySystemError::new_err(\"null result\")));\n}","typeGuard":"fn valid_pyobject(ptr: *mut ffi::PyObject) -> bool { !ptr.is_null() }","tryCatchPattern":"// prefer fallible constructors\nlet obj: PyResult<Py<PyAny>> = unsafe { Py::from_owned_ptr_or_err(py, ptr) };","preventionTips":["Use *_or_err FFI wrappers instead of infallible *_ptr variants","Check the Python error indicator after every fallible C API call","Never call Python C APIs during interpreter shutdown"],"tags":["ffi","null-pointer","pyerr","panic"],"backgroundTag":"null-pyobject-pointer","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"}