{"record":{"id":"3ba9a7ada9aaf753","repo":"PyO3/pyo3","slug":"unexpected-type-in-mro-attribute","errorCode":null,"errorMessage":"Unexpected type in `__mro__` attribute.","messagePattern":"Unexpected type in `__mro__` attribute\\.","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/types/typeobject.rs","lineNumber":223,"sourceCode":"\n    /// Checks whether `self` is a subclass of type `T`.\n    ///\n    /// Equivalent to the Python expression `issubclass(self, T)`, if the type\n    /// `T` is known at compile time.\n    fn is_subclass_of<T>(&self) -> PyResult<bool>\n    where\n        T: PyTypeInfo,\n    {\n        self.is_subclass(&T::type_object(self.py()))\n    }\n\n    fn mro(&self) -> Bound<'py, PyTuple> {\n        #[cfg(any(Py_LIMITED_API, PyPy))]\n        let mro = self\n            .getattr(intern!(self.py(), \"__mro__\"))\n            .expect(\"Cannot get `__mro__` from object.\")\n            .extract()\n            .expect(\"Unexpected type in `__mro__` attribute.\");\n\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__\"))","sourceCodeStart":205,"sourceCodeEnd":241,"githubUrl":"https://github.com/PyO3/pyo3/blob/ac9b6899d348be4d54614d060dea53a645a12e36/src/types/typeobject.rs#L205-L241","documentation":"The sibling panic to error 101 in `PyTypeMethods::mro()`: under the limited API or PyPy, pyo3 fetches `__mro__` via `getattr` and then `.extract::<Bound<PyTuple>>()`. This `.expect` fires when `__mro__` exists but is not a tuple of type objects, so extraction fails.","triggerScenarios":"Calling `.mro()` on a type-like object whose `__mro__` attribute is present but has a non-tuple value (custom metaclass or shadowing attribute) under `Py_LIMITED_API` or PyPy.","commonSituations":"Custom metaclasses or monkey-patched classes that override `__mro__` with something unexpected; unusual embedding environments where the 'type' wrapper actually wraps a non-type object with a `__mro__`-like attribute.","solutions":["Ensure the wrapped object is a real type and nothing shadows `__mro__` with a non-tuple","Extract manually with graceful handling: `getattr(\"__mro__\")` then `downcast::<PyTuple>()` and handle the error","Remove or fix custom `__mro__` overrides on the class"],"exampleFix":"// before\nlet mro = ty.mro(); // panics if __mro__ is not a tuple\n// after\nlet mro = ty.getattr(\"__mro__\")?.downcast_into::<PyTuple>().ok();","handlingStrategy":"type-guard","validationCode":"let ok = ty.getattr(\"__mro__\").map(|a| a.is_instance_of::<PyTuple>()).unwrap_or(false);\nif !ok { return Err(\"object has no tuple __mro__\"); }","typeGuard":"fn has_tuple_mro(ty: &Bound<'_, PyAny>) -> bool {\n    ty.getattr(\"__mro__\").map(|a| a.downcast::<PyTuple>().is_ok()).unwrap_or(false)\n}","tryCatchPattern":"let mro = ty.getattr(\"__mro__\")\n    .and_then(|a| a.downcast_into::<PyTuple>())\n    .map_err(|e| format!(\"malformed __mro__: {e}\"))?;","preventionTips":["Avoid metaclasses that override `__mro__` with non-tuple values","Validate third-party classes before reflecting on them","Prefer the non-limited-API build on CPython where `tp_mro` is read directly"],"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"}