PyO3/pyo3 · error
Already borrowed
Error message
Already borrowed
What it means
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.
Source
Thrown at src/pycell.rs:588
pub fn as_ptr(&self) -> *mut ffi::PyObject {
self.inner.as_ptr()
}
/// Returns an owned raw FFI pointer represented by self.
///
/// # Safety
///
/// The reference is owned; when finished the caller should either transfer ownership
/// of the pointer or decrease the reference count (e.g. with [`pyo3::ffi::Py_DecRef`](crate::ffi::Py_DecRef)).
#[inline]
pub fn into_ptr(self) -> *mut ffi::PyObject {
self.inner.clone().into_ptr()
}
#[inline]
#[track_caller]
pub(crate) fn borrow(obj: &Bound<'py, T>) -> Self {
Self::try_borrow(obj).expect("Already borrowed")
}
pub(crate) fn try_borrow(obj: &Bound<'py, T>) -> Result<Self, PyBorrowMutError> {
let cell = obj.get_class_object();
cell.ensure_threadsafe();
cell.borrow_checker()
.try_borrow_mut()
.map(|_| Self { inner: obj.clone() })
}
pub(crate) fn downgrade(slf: &Self) -> &PyRef<'py, T> {
let ptr = NonNull::from(slf).cast();
// SAFETY: `PyRefMut<T>` and `PyRef<T>` have the same layout
unsafe { ptr.as_ref() }
}
}
impl<'p, T> PyRefMut<'p, T>View on GitHub (pinned to ac9b6899d3)
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
Example fix
// before let r = obj.borrow(py); r.method_mut(py); // still shared-borrowed -> panic // after drop(obj.borrow(py)); obj.borrow_mut(py).method_mut();
Defensive patterns
Strategy: try-catch
Validate before calling
// Rust let _ = obj.try_borrow_mut(py).map_err(PyErr::from)?;
Try / catch
// Rust
match obj.try_borrow_mut(py) {
Ok(mut m) => { /* work */ },
Err(_) => return Err(PyBorrowMutError::new().into()),
} Prevention
- 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
When it happens
Trigger: 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`.
Common situations: 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.
Related errors
- Already mutably borrowed
- this object is already borrowed
- this object is already borrowed
- Neither abi3 or abi3t features are enabled
- Cannot target an abi3t version below {MINIMUM_SUPPORTED_VERS
AI-assisted analysis of PyO3/pyo3@ac9b6899d3 (2026-09-05).
Data as JSON: /api/errors/1f7a8d12c7004279.
Report an issue: GitHub.