PyO3/pyo3 · error
Unexpected type in `__bases__` attribute.
Error message
Unexpected type in `__bases__` attribute.
What it means
The sibling panic to error 103 in `PyTypeMethods::bases()`: under the limited API or PyPy, pyo3 fetches `__bases__` and then extracts it as `Bound<PyTuple>`. This `.expect` fires when the attribute exists but its value is not a tuple, so the extraction fails.
Source
Thrown at src/types/typeobject.rs:244
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)]
mod tests {
use crate::test_utils::generate_unique_module_name;View on GitHub (pinned to ac9b6899d3)
Solutions
- Ensure the class's `__bases__` is a proper tuple of type objects
- Extract defensively via `downcast_into::<PyTuple>()` instead of the panicking accessor
- Fix the class definition or metaclass that produces the malformed `__bases__`
Example fix
// before
let bases = ty.bases(); // panics if __bases__ is not a tuple
// after
let bases = ty.getattr("__bases__")?.downcast_into::<PyTuple>().ok(); Defensive patterns
Strategy: type-guard
Validate before calling
let ok = ty.getattr("__bases__").map(|a| a.is_instance_of::<PyTuple>()).unwrap_or(false);
if !ok { return Err("object has no tuple __bases__"); } Type guard
fn has_tuple_bases(ty: &Bound<'_, PyAny>) -> bool {
ty.getattr("__bases__").map(|a| a.downcast::<PyTuple>().is_ok()).unwrap_or(false)
} Try / catch
let bases = ty.getattr("__bases__")
.and_then(|a| a.downcast_into::<PyTuple>())
.map_err(|e| format!("malformed __bases__: {e}"))?; Prevention
- Ensure class definitions always produce tuple-typed `__bases__` (standard metaclasses do)
- Audit dynamically constructed/patched classes before reflection
- Prefer CPython non-limited builds where `tp_bases` is read directly from the type object
When it happens
Trigger: Calling `.bases()` on an object whose `__bases__` attribute is set to a non-tuple value (e.g. a list or single object) under `Py_LIMITED_API` or PyPy.
Common situations: Classes from exotic metaclass frameworks or hand-constructed type objects where `__bases__` was assigned incorrectly; wrapped pseudo-type objects in embedding code.
Related errors
- Cannot get `__mro__` from object.
- Unexpected type in `__mro__` attribute.
- Cannot get `__bases__` from object.
- 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/5677d64b3f8b1091.
Report an issue: GitHub.