{"record":{"id":"5b89ec42d496a4ca","repo":"quickwit-oss/quickwit","slug":"the-left-iterator-should-not-be-empty","errorCode":null,"errorMessage":"The left iterator should not be empty.","messagePattern":"The left iterator should not be empty\\.","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"quickwit/quickwit-common/src/sorted_iter.rs","lineNumber":62,"sourceCode":"    right: Peekable<U>,\n}\n\nimpl<T, U, K> Iterator for DiffIterator<T, U>\nwhere\n    T: Iterator<Item = K>,\n    U: Iterator<Item = K>,\n    K: Ord,\n{\n    type Item = Diff<K>;\n\n    fn next(&mut self) -> Option<Self::Item> {\n        match (self.left.peek(), self.right.peek()) {\n            (Some(left), Some(right)) => match left.cmp(right) {\n                Ordering::Less => {\n                    let left = self\n                        .left\n                        .next()\n                        .expect(\"The left iterator should not be empty.\");\n                    Some(Diff::Removed(left))\n                }\n                Ordering::Equal => {\n                    let left = self\n                        .left\n                        .next()\n                        .expect(\"The left iterator should not be empty.\");\n                    self.right.next();\n                    Some(Diff::Unchanged(left))\n                }\n                Ordering::Greater => {\n                    let right = self\n                        .right\n                        .next()\n                        .expect(\"The right iterator should not be empty.\");\n                    Some(Diff::Added(right))\n                }\n            },","sourceCodeStart":44,"sourceCodeEnd":80,"githubUrl":"https://github.com/quickwit-oss/quickwit/blob/a39730c5cdcd1a4fe798403737ae293999ea21f8/quickwit/quickwit-common/src/sorted_iter.rs#L44-L80","documentation":"In SortedDiffIterator::next, when both iterators peek as Some and left < right, the code calls self.left.next() and asserts it returns an item. Since peek() already returned Some, this can only fail if the underlying iterator misbehaves (returns Some on peek but None on next) — a violation of the Iterator contract.","triggerScenarios":"Iterating a SortedIterator diff where the left iterator's peek() and next() disagree — only possible with a buggy/hand-rolled iterator that does not honor peek semantics, or interior mutation of the iterator during iteration.","commonSituations":"Custom Peekable-wrapped iterators that mutate shared state in next(); concurrent modification of the underlying collection while diffing; regression in sorted_iter.rs itself.","solutions":["Ensure the left iterator faithfully implements Iterator (peek(Some) implies next() yields an item)","Do not mutate the underlying collection or the iterator while diffing","Check for concurrent access; SortedIterator is not synchronization — wrap in a lock if shared","If it persists, file/regress-fix in quickwit-common::sorted_iter"],"exampleFix":"// before\nlet left = self.left.next().expect(\"The left iterator should not be empty.\");\n// after\nlet left = match self.left.next() { Some(l) => l, None => return None }; // degrade gracefully instead of panicking","handlingStrategy":"type-guard","validationCode":"// Validate iterator contract before diffing: drain into a Vec first\nlet left_items: Vec<_> = left.collect(); // then rebuild iterator\nassert_eq!(left_items.len(), /* expected */ left_items.len());","typeGuard":"fn is_consistent<I: Iterator + Clone>(it: &I) -> bool { it.clone().peekable().peek().is_some() }","tryCatchPattern":"std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| diff.for_each(|d| process(d)))).unwrap_or_else(|_| eprintln!(\"diff failed: iterator contract violation\"));","preventionTips":["Only pass well-formed iterators (peek(Some) implies next yields) into SortedIterator","Snapshot collections into Vecs before diffing live data","Never mutate the underlying collection during the diff","Do not share the iterator across threads without synchronization"],"tags":["rust","iterator","invariant","peekable"],"backgroundTag":"internal-invariant-violation","analyzedSha":"a39730c5cdcd1a4fe798403737ae293999ea21f8","analyzedAt":"2026-09-08T13:19:37.784Z","contentChangedAt":"2026-09-08T13:19:37.784Z","schemaVersion":2},"datasetVersion":"2026-09-17T15:17:12.973Z"}