{"record":{"id":"6603801bcbd91e62","repo":"PyO3/pyo3","slug":"cannot-attach-to-the-python-interpreter-while-it-i","errorCode":null,"errorMessage":"Cannot attach to the Python interpreter while it is finalizing.","messagePattern":"Cannot attach to the Python interpreter while it is finalizing\\.","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/internal/state.rs","lineNumber":81,"sourceCode":"    ///\n    /// If the thread was already attached via PyO3, this returns\n    /// `AttachGuard::Assumed`. Otherwise, the thread will attach now and\n    /// `AttachGuard::Ensured` will be returned.\n    pub(crate) fn attach() -> Self {\n        match Self::try_attach() {\n            Ok(guard) => guard,\n            Err(AttachError::ForbiddenDuringTraverse) => {\n                panic!(\"{}\", ForbidAttaching::FORBIDDEN_DURING_TRAVERSE)\n            }\n            Err(AttachError::NotInitialized) => {\n                // try to initialize the interpreter and try again\n                crate::interpreter_lifecycle::ensure_initialized();\n                // SAFETY: just initialized the interpreter\n                unsafe { Self::do_attach_unchecked() }\n            }\n            #[cfg(Py_3_13)]\n            Err(AttachError::Finalizing) => {\n                panic!(\"Cannot attach to the Python interpreter while it is finalizing.\");\n            }\n        }\n    }\n\n    /// Variant of the above which will will return gracefully if the interpreter cannot be attached to.\n    pub(crate) fn try_attach() -> Result<Self, AttachError> {\n        match ATTACH_COUNT.try_with(|c| c.get()) {\n            Ok(i) if i > 0 => {\n                // SAFETY: We just checked that the thread is already attached.\n                return Ok(unsafe { Self::assume() });\n            }\n            // Cannot attach during GC traversal.\n            Ok(ATTACH_FORBIDDEN_DURING_TRAVERSE) => {\n                return Err(AttachError::ForbiddenDuringTraverse)\n            }\n            // other cases handled below\n            _ => {}\n        }","sourceCodeStart":63,"sourceCodeEnd":99,"githubUrl":"https://github.com/PyO3/pyo3/blob/ac9b6899d348be4d54614d060dea53a645a12e36/src/internal/state.rs#L63-L99","documentation":"This panic fires from Python::attach()/AttachGuard::attach when the interpreter has begun finalizing (Python 3.13+, via AttachError::Finalizing). Once CPython is shutting down, attaching a thread to obtain the GIL is unsafe and undefined, so PyO3 refuses with a panic instead of blocking forever or crashing in C code.","triggerScenarios":"Calling Python::with_gil / Python::attach during interpreter shutdown: destructors/drop handlers running after Py_Finalize, daemon threads still executing Python calls, atexit or __del__ code that re-enters PyO3 late in teardown.","commonSituations":"Background worker threads (rayon/tokio/std threads) still alive when the embedding application or interpreter calls Py_Finalize; objects dropped in process exit paths; long-lived caches flushed after finalization started.","solutions":["Ensure worker threads are joined/stopped before Py_Finalize or process exit","Use Python::with_embedded_python_interpreter/teardown utilities that shut threads down first","Check the interpreter isn't finalizing with Python::version/pool guards — use try_attach-based APIs (Python::try_attach) and skip work on error","In 3.13+ embeddings, call Py_Finalize only after all PyO3-using threads have terminated"],"exampleFix":"// before\nstd::thread::spawn(|| Python::with_gil(|py| run(py))); // may run during finalize\n// after\nlet handle = std::thread::spawn(|| Python::with_gil(|py| run(py)));\nhandle.join().expect(\"worker\");\n// then finalize the interpreter","handlingStrategy":"validation","validationCode":"// PyO3 0.23+: check via pool/attach result before work\nif pyo3::Python::try_attach().is_none() { return; } // skip if not attachable","typeGuard":"fn interpreter_usable() -> bool { pyo3::Python::try_attach().is_some() }","tryCatchPattern":"std::panic::catch_unwind(|| pyo3::Python::with_gil(|py| work(py))).unwrap_or_default();","preventionTips":["Join all Python-touching threads before Py_Finalize / process exit","Stop background workers (rayon/tokio) during interpreter teardown","Avoid Python calls in Drop impls that may run at shutdown"],"tags":["pyo3","gil","interpreter-finalization","shutdown","panic"],"backgroundTag":"attach-during-interpreter-finalization","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"}