{"record":{"id":"1f7a8d12c7004279","repo":"PyO3/pyo3","slug":"already-borrowed","errorCode":null,"errorMessage":"Already borrowed","messagePattern":"Already borrowed","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/pycell.rs","lineNumber":588,"sourceCode":"    pub fn as_ptr(&self) -> *mut ffi::PyObject {\n        self.inner.as_ptr()\n    }\n\n    /// Returns an owned raw FFI pointer represented by self.\n    ///\n    /// # Safety\n    ///\n    /// The reference is owned; when finished the caller should either transfer ownership\n    /// of the pointer or decrease the reference count (e.g. with [`pyo3::ffi::Py_DecRef`](crate::ffi::Py_DecRef)).\n    #[inline]\n    pub fn into_ptr(self) -> *mut ffi::PyObject {\n        self.inner.clone().into_ptr()\n    }\n\n    #[inline]\n    #[track_caller]\n    pub(crate) fn borrow(obj: &Bound<'py, T>) -> Self {\n        Self::try_borrow(obj).expect(\"Already borrowed\")\n    }\n\n    pub(crate) fn try_borrow(obj: &Bound<'py, T>) -> Result<Self, PyBorrowMutError> {\n        let cell = obj.get_class_object();\n        cell.ensure_threadsafe();\n        cell.borrow_checker()\n            .try_borrow_mut()\n            .map(|_| Self { inner: obj.clone() })\n    }\n\n    pub(crate) fn downgrade(slf: &Self) -> &PyRef<'py, T> {\n        let ptr = NonNull::from(slf).cast();\n        // SAFETY: `PyRefMut<T>` and `PyRef<T>` have the same layout\n        unsafe { ptr.as_ref() }\n    }\n}\n\nimpl<'p, T> PyRefMut<'p, T>","sourceCodeStart":570,"sourceCodeEnd":606,"githubUrl":"https://github.com/PyO3/pyo3/blob/ac9b6899d348be4d54614d060dea53a645a12e36/src/pycell.rs#L570-L606","documentation":"Symmetric to the mutable-borrow panic: `PyRefMut::borrow` panics with 'Already borrowed' when requesting a mutable borrow while the object is already shared-borrowed (one or more `PyRef`s alive). PyO3 enforces at runtime the same rules the Rust compiler enforces at compile time for `&`/`&mut`, since Python re-entrancy can create aliases the compiler cannot see.","triggerScenarios":"Two Python references to the same `#[pyclass]` object with both `&self` and `&mut self` methods active simultaneously, e.g. calling a `&self` method whose result callback enters a `&mut self` method on the same instance; holding a `PyRef` while calling `pyo3::py_run!`/attribute assignment that needs `PyRefMut`.","commonSituations":"Python-level property setters (`&mut self`) invoked while a getter's `PyRef` is still held; nested iteration over the same object; callbacks fired from within a shared-borrow scope.","solutions":["Drop the `PyRef` before calling the `&mut self` method","Use `try_borrow_mut` and handle the `PyBorrowMutError` gracefully","Clone needed data out of the immutable borrow first, then take the mutable one","Use `py.allow_threads` or interior mutability (`RefCell`/locks) to avoid overlapping borrows"],"exampleFix":"// before\nlet r = obj.borrow(py);\nr.method_mut(py); // still shared-borrowed -> panic\n// after\ndrop(obj.borrow(py));\nobj.borrow_mut(py).method_mut();","handlingStrategy":"try-catch","validationCode":"// Rust\nlet _ = obj.try_borrow_mut(py).map_err(PyErr::from)?;","typeGuard":null,"tryCatchPattern":"// Rust\nmatch obj.try_borrow_mut(py) {\n    Ok(mut m) => { /* work */ },\n    Err(_) => return Err(PyBorrowMutError::new().into()),\n}","preventionTips":["Drop PyRef before requesting a mutable borrow","Avoid attribute setters (&mut self) while getters hold borrows","Clone data out of shared borrows first","Use interior mutability for shared state"],"tags":["rust","pyo3","borrow-checker","pyrefmut"],"backgroundTag":"already-borrowed-pyclass","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"}