{"record":{"id":"e080c7c5d4587d21","repo":"PyO3/pyo3","slug":"this-object-is-already-borrowed","errorCode":null,"errorMessage":"this object is already borrowed","messagePattern":"this object is already borrowed","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/pycell.rs","lineNumber":393,"sourceCode":"        let t_not_frozen = !<T::Frozen as crate::pyclass::boolean_struct::private::Boolean>::VALUE;\n        let u_frozen = <<T::BaseType as PyClass>::Frozen as crate::pyclass::boolean_struct::private::Boolean>::VALUE;\n        if t_not_frozen && u_frozen {\n            // If `T` is mutable subclass of `U` differ, then it is possible that we need to\n            // release the borrow count now. (e.g. `U` may have a noop borrow checker so\n            // dropping the `PyRef<U>` later would noop and leak the borrow we currently hold.)\n            //\n            // However it's nontrivial, if `U` itself has a mutable base class `V`,\n            // then the borrow checker of both `T` and `U` is the shared borrow checker of `V`.\n            //\n            // But it's really hard to prove that in the type system, the soundest thing we\n            // can do is just add a borrow to `U` now and then release the borrow of `T`.\n\n            self.inner\n                .as_super()\n                .get_class_object()\n                .borrow_checker()\n                .try_borrow()\n                .expect(\"this object is already borrowed\");\n\n            self.inner\n                .get_class_object()\n                .borrow_checker()\n                .release_borrow()\n        };\n        PyRef {\n            inner: unsafe {\n                ManuallyDrop::new(self)\n                    .as_ptr()\n                    .assume_owned_unchecked(py)\n                    .cast_into_unchecked()\n            },\n        }\n    }\n\n    /// Borrows a shared reference to `PyRef<T::BaseType>`.\n    ///","sourceCodeStart":375,"sourceCodeEnd":411,"githubUrl":"https://github.com/PyO3/pyo3/blob/ac9b6899d348be4d54614d060dea53a645a12e36/src/pycell.rs#L375-L411","documentation":"`PyClassGuard::into_super` converts a guard of a subclass `T` into a guard of its pyo3 base class `U`. To keep borrow counts consistent it first adds a shared borrow on the base (`try_borrow`, panicking with 'this object is already borrowed' if the base is mutably borrowed) and then releases the borrow of `T`. The panic means the base-class object's borrow state conflicts with the conversion.","triggerScenarios":"Calling `into_super()` while the base class portion is mutably borrowed (`PyRefMut` of the base alive); overlapping guards for base and derived instances of the same underlying object; nested `into_super` calls inside methods that already hold mutable borrows.","commonSituations":"Multi-level `#[pyclass(extends=...)]` hierarchies with methods on both base and subclass calling each other; Python subclass method calling `super()`-like Rust conversions while the base is mutably accessed.","solutions":["Ensure no `PyRefMut` of the base class is alive when calling `into_super`","Convert guards to the base only from an immutable (`PyRef`) state","Use `try_borrow`-based explicit checks before converting","Restructure to avoid calling `into_super` while a base method is executing"],"exampleFix":"// before\nfn method(mut this: PyRefMut<'_, Self>) -> PyResult<()> {\n    let base = this.into_super(); // base already mutably borrowed\n    base.base_method()\n}\n// after\nfn method(this: PyRef<'_, Self>) -> PyResult<()> {\n    let base = this.into_super();\n    base.base_method()\n}","handlingStrategy":"type-guard","validationCode":"// Rust: ensure base is not mutably borrowed before into_super\n// (call into_super only from PyRef, not PyRefMut)","typeGuard":"fn can_take_super<'py, T: PyClass>(obj: &Bound<'py, T>) -> bool {\n    obj.try_borrow().is_ok()\n}","tryCatchPattern":null,"preventionTips":["Call into_super from immutable guards only","Avoid overlapping base and subclass guards","Restructure methods so base mutation is not concurrent","Prefer try_borrow checks in hierarchy navigation"],"tags":["rust","pyo3","inheritance","borrow-checker"],"backgroundTag":"pyclass-super-borrow-conflict","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"}