{"record":{"id":"45641a7b6233d5b6","repo":"PyO3/pyo3","slug":"cannot-get-bases-from-object","errorCode":null,"errorMessage":"Cannot get `__bases__` from object.","messagePattern":"Cannot get `__bases__` from object\\.","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/types/typeobject.rs","lineNumber":242,"sourceCode":"\n        #[cfg(not(any(Py_LIMITED_API, PyPy)))]\n        let mro = unsafe {\n            use crate::ffi_ptr_ext::FfiPtrExt;\n            (*self.as_type_ptr())\n                .tp_mro\n                .assume_borrowed(self.py())\n                .to_owned()\n                .cast_into_unchecked()\n        };\n\n        mro\n    }\n\n    fn bases(&self) -> Bound<'py, PyTuple> {\n        #[cfg(any(Py_LIMITED_API, PyPy))]\n        let bases = self\n            .getattr(intern!(self.py(), \"__bases__\"))\n            .expect(\"Cannot get `__bases__` from object.\")\n            .extract()\n            .expect(\"Unexpected type in `__bases__` attribute.\");\n\n        #[cfg(not(any(Py_LIMITED_API, PyPy)))]\n        let bases = unsafe {\n            use crate::ffi_ptr_ext::FfiPtrExt;\n            (*self.as_type_ptr())\n                .tp_bases\n                .assume_borrowed(self.py())\n                .to_owned()\n                .cast_into_unchecked()\n        };\n\n        bases\n    }\n}\n\n#[cfg(test)]","sourceCodeStart":224,"sourceCodeEnd":260,"githubUrl":"https://github.com/PyO3/pyo3/blob/ac9b6899d348be4d54614d060dea53a645a12e36/src/types/typeobject.rs#L224-L260","documentation":"`PyTypeMethods::bases()` returns the type's direct base classes. Under the limited API or PyPy (where `tp_bases` is not accessible), it reads the `__bases__` attribute and panics with this message if `getattr` fails — i.e. the wrapped object does not expose `__bases__`, meaning it is not a proper Python type.","triggerScenarios":"Calling `.bases()` on a `PyTypeMethods` receiver whose underlying object lacks a `__bases__` attribute, while compiled with `Py_LIMITED_API` or running on PyPy.","commonSituations":"abi3/limited-API builds or PyPy runs where code passes a non-type object (e.g. an instance or a builtin wrapper) where a real class was expected.","solutions":["Verify the object is a Python type (`isinstance(obj, type)`) before calling `.bases()`","Use `getattr(\"__bases__\")` with error handling instead of the panicking accessor","Compile against CPython without Py_LIMITED_API to use the direct `tp_bases` field"],"exampleFix":"// before\nlet bases = ty.bases(); // panics if __bases__ missing under limited API/PyPy\n// after\nlet bases = ty.getattr(\"__bases__\").ok()\n    .map(|a| a.extract::<Bound<PyTuple>>().expect(\"__bases__ not a tuple\"));","handlingStrategy":"type-guard","validationCode":"if !obj.is_instance_of::<crate::types::PyType>() {\n    return Err(\"bases() requires a real Python type\");\n}","typeGuard":"fn is_real_type(obj: &Bound<'_, PyAny>) -> bool {\n    obj.downcast::<crate::types::PyType>().is_ok()\n}","tryCatchPattern":"let bases = ty.getattr(\"__bases__\")\n    .and_then(|a| a.downcast_into::<PyTuple>())\n    .map_err(|e| format!(\"no usable __bases__: {e}\"))?;","preventionTips":["Never pass instances where a class is expected; use `obj.get_type()` first","Cover PyPy/abi3 builds in CI where the `getattr(\"__bases__\")` fallback runs","Handle errors from reflection APIs explicitly instead of relying on pyo3's panics"],"tags":["rust","pyo3","pypy","limited-api","types"],"backgroundTag":"missing-dunder-attribute","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"}