{"record":{"id":"5677d64b3f8b1091","repo":"PyO3/pyo3","slug":"unexpected-type-in-bases-attribute","errorCode":null,"errorMessage":"Unexpected type in `__bases__` attribute.","messagePattern":"Unexpected type in `__bases__` attribute\\.","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/types/typeobject.rs","lineNumber":244,"sourceCode":"        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)]\nmod tests {\n    use crate::test_utils::generate_unique_module_name;","sourceCodeStart":226,"sourceCodeEnd":262,"githubUrl":"https://github.com/PyO3/pyo3/blob/ac9b6899d348be4d54614d060dea53a645a12e36/src/types/typeobject.rs#L226-L262","documentation":"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.","triggerScenarios":"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.","commonSituations":"Classes from exotic metaclass frameworks or hand-constructed type objects where `__bases__` was assigned incorrectly; wrapped pseudo-type objects in embedding code.","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__`"],"exampleFix":"// before\nlet bases = ty.bases(); // panics if __bases__ is not a tuple\n// after\nlet bases = ty.getattr(\"__bases__\")?.downcast_into::<PyTuple>().ok();","handlingStrategy":"type-guard","validationCode":"let ok = ty.getattr(\"__bases__\").map(|a| a.is_instance_of::<PyTuple>()).unwrap_or(false);\nif !ok { return Err(\"object has no tuple __bases__\"); }","typeGuard":"fn has_tuple_bases(ty: &Bound<'_, PyAny>) -> bool {\n    ty.getattr(\"__bases__\").map(|a| a.downcast::<PyTuple>().is_ok()).unwrap_or(false)\n}","tryCatchPattern":"let bases = ty.getattr(\"__bases__\")\n    .and_then(|a| a.downcast_into::<PyTuple>())\n    .map_err(|e| format!(\"malformed __bases__: {e}\"))?;","preventionTips":["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"],"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"}