{"record":{"id":"9aa8c5b660ffb901","repo":"PyO3/pyo3","slug":"frozenset-iteration-should-be-infallible","errorCode":null,"errorMessage":"frozenset iteration should be infallible","messagePattern":"frozenset iteration should be infallible","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/types/frozenset.rs","lineNumber":238,"sourceCode":"}\n\n/// PyO3 implementation of an iterator for a Python `frozenset` object.\npub struct BoundFrozenSetIterator<'py>(Bound<'py, PyIterator>);\n\nimpl<'py> BoundFrozenSetIterator<'py> {\n    pub(super) fn new(set: Bound<'py, PyFrozenSet>) -> Self {\n        Self(PyIterator::from_object(&set).expect(\"frozenset should always be iterable\"))\n    }\n}\n\nimpl<'py> Iterator for BoundFrozenSetIterator<'py> {\n    type Item = Bound<'py, super::PyAny>;\n\n    /// Advances the iterator and returns the next value.\n    fn next(&mut self) -> Option<Self::Item> {\n        self.0\n            .next()\n            .map(|result| result.expect(\"frozenset iteration should be infallible\"))\n    }\n\n    fn size_hint(&self) -> (usize, Option<usize>) {\n        let len = ExactSizeIterator::len(self);\n        (len, Some(len))\n    }\n\n    #[inline]\n    fn count(self) -> usize\n    where\n        Self: Sized,\n    {\n        self.len()\n    }\n}\n\nimpl ExactSizeIterator for BoundFrozenSetIterator<'_> {\n    fn len(&self) -> usize {","sourceCodeStart":220,"sourceCodeEnd":256,"githubUrl":"https://github.com/PyO3/pyo3/blob/ac9b6899d348be4d54614d060dea53a645a12e36/src/types/frozenset.rs#L220-L256","documentation":"PyO3 wraps Python's frozenset iterator and asserts that each step of iteration cannot fail, since iterating a frozenset over which the interpreter holds a borrowed reference is guaranteed to yield items without error. The Rust `next()` unwraps the inner PyResult with `.expect()`, so if the underlying C-API iteration ever returns an error this panic fires, indicating an interpreter invariant violation rather than user error.","triggerScenarios":"Calling `.next()` on a `BoundSetIterator`/frozenset iterator (e.g. via `frozenset.iter()` in Rust or any `for` loop over a `&PyFrozenSet`) when the underlying CPython iterator returns an error — practically only when the CPython interpreter state is corrupt, the object was mutated/freed improperly, or an FFI misuse broke the iterator.","commonSituations":"Unsafe FFI code invalidating the frozenset or its iterator, embedding CPython in a host app where object refcounts were mishandled, or running against a non-CPython interpreter (RustPython/GraalPy) whose iterator error behavior diverges from CPython's.","solutions":["Audit code for unsafe manipulation or premature deallocation of the frozenset/iterator while iterating","Verify the Python interpreter build/embedding setup is standard CPython and refcounts are not corrupted","Report to pyo3 if reproducible on a supported interpreter, with a minimal reproducer"],"exampleFix":"// before: panic propagates out of iterator\nfor item in frozenset.iter() { ... }\n// after: iterate defensively over a plain Python iteration and handle errors\nlet it = frozenset.as_any().call_method0(\"__iter__\")?;\nwhile let Some(item) = it.call_method0(\"__next__\").transpose()? { /* use item */ }","handlingStrategy":"try-catch","validationCode":"// Python-side sanity check before Rust iteration\nif not isinstance(fs, frozenset):\n    raise TypeError(\"expected frozenset\")","typeGuard":"fn is_frozenset(obj: &Bound<'_, PyAny>) -> bool {\n    obj.downcast::<PyFrozenSet>().is_ok()\n}","tryCatchPattern":"// use fallible iteration instead of the panicking wrapper\nlet it = obj.call_method0(\"__iter__\")?;\nloop {\n    match it.call_method0(\"__next__\") {\n        Ok(item) => { /* use item */ }\n        Err(e) if e.is_instance_of::<PyStopIteration>(py) => break,\n        Err(e) => return Err(e),\n    }\n}","preventionTips":["Use checked downcasts (downcast/extract) before iterating","Never mutate or free collections from callbacks while Rust iterates them","Test on the actual target interpreter (CPython vs RustPython/GraalPy)"],"tags":["pyo3","iterator","panic","frozenset"],"backgroundTag":"iterator-infallibility-panic","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"}