PyO3/pyo3 · error
Cannot get `__bases__` from object.
Error message
Cannot get `__bases__` from object.
What it means
`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.
Source
Thrown at src/types/typeobject.rs:242
#[cfg(not(any(Py_LIMITED_API, PyPy)))]
let mro = unsafe {
use crate::ffi_ptr_ext::FfiPtrExt;
(*self.as_type_ptr())
.tp_mro
.assume_borrowed(self.py())
.to_owned()
.cast_into_unchecked()
};
mro
}
fn bases(&self) -> Bound<'py, PyTuple> {
#[cfg(any(Py_LIMITED_API, PyPy))]
let bases = self
.getattr(intern!(self.py(), "__bases__"))
.expect("Cannot get `__bases__` from object.")
.extract()
.expect("Unexpected type in `__bases__` attribute.");
#[cfg(not(any(Py_LIMITED_API, PyPy)))]
let bases = unsafe {
use crate::ffi_ptr_ext::FfiPtrExt;
(*self.as_type_ptr())
.tp_bases
.assume_borrowed(self.py())
.to_owned()
.cast_into_unchecked()
};
bases
}
}
#[cfg(test)]View on GitHub (pinned to ac9b6899d3)
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
Example fix
// before
let bases = ty.bases(); // panics if __bases__ missing under limited API/PyPy
// after
let bases = ty.getattr("__bases__").ok()
.map(|a| a.extract::<Bound<PyTuple>>().expect("__bases__ not a tuple")); Defensive patterns
Strategy: type-guard
Validate before calling
if !obj.is_instance_of::<crate::types::PyType>() {
return Err("bases() requires a real Python type");
} Type guard
fn is_real_type(obj: &Bound<'_, PyAny>) -> bool {
obj.downcast::<crate::types::PyType>().is_ok()
} Try / catch
let bases = ty.getattr("__bases__")
.and_then(|a| a.downcast_into::<PyTuple>())
.map_err(|e| format!("no usable __bases__: {e}"))?; Prevention
- 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
When it happens
Trigger: Calling `.bases()` on a `PyTypeMethods` receiver whose underlying object lacks a `__bases__` attribute, while compiled with `Py_LIMITED_API` or running on PyPy.
Common situations: 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.
Related errors
- Cannot get `__mro__` from object.
- Unexpected type in `__mro__` attribute.
- Unexpected type in `__bases__` attribute.
- 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/45641a7b6233d5b6.
Report an issue: GitHub.