quickwit-oss/quickwit · error

The left iterator should not be empty.

Error message

The left iterator should not be empty.

What it means

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.

Solutions

  1. Ensure the left iterator faithfully implements Iterator (peek(Some) implies next() yields an item)
  2. Do not mutate the underlying collection or the iterator while diffing
  3. Check for concurrent access; SortedIterator is not synchronization — wrap in a lock if shared
  4. If it persists, file/regress-fix in quickwit-common::sorted_iter

Example fix

// before
let left = self.left.next().expect("The left iterator should not be empty.");
// after
let left = match self.left.next() { Some(l) => l, None => return None }; // degrade gracefully instead of panicking
Defensive patterns

Strategy: type-guard

Validate before calling

// Validate iterator contract before diffing: drain into a Vec first
let left_items: Vec<_> = left.collect(); // then rebuild iterator
assert_eq!(left_items.len(), /* expected */ left_items.len());

Type guard

fn is_consistent<I: Iterator + Clone>(it: &I) -> bool { it.clone().peekable().peek().is_some() }

Try / catch

std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| diff.for_each(|d| process(d)))).unwrap_or_else(|_| eprintln!("diff failed: iterator contract violation"));

Prevention

When it happens

Trigger: 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.

Common situations: Custom Peekable-wrapped iterators that mutate shared state in next(); concurrent modification of the underlying collection while diffing; regression in sorted_iter.rs itself.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


AI-assisted analysis of quickwit-oss/quickwit@a39730c5cd (2026-09-08). Data as JSON: /api/errors/5b89ec42d496a4ca. Report an issue: GitHub.

Appendix: source

Thrown at quickwit/quickwit-common/src/sorted_iter.rs:62

    right: Peekable<U>,
}

impl<T, U, K> Iterator for DiffIterator<T, U>
where
    T: Iterator<Item = K>,
    U: Iterator<Item = K>,
    K: Ord,
{
    type Item = Diff<K>;

    fn next(&mut self) -> Option<Self::Item> {
        match (self.left.peek(), self.right.peek()) {
            (Some(left), Some(right)) => match left.cmp(right) {
                Ordering::Less => {
                    let left = self
                        .left
                        .next()
                        .expect("The left iterator should not be empty.");
                    Some(Diff::Removed(left))
                }
                Ordering::Equal => {
                    let left = self
                        .left
                        .next()
                        .expect("The left iterator should not be empty.");
                    self.right.next();
                    Some(Diff::Unchanged(left))
                }
                Ordering::Greater => {
                    let right = self
                        .right
                        .next()
                        .expect("The right iterator should not be empty.");
                    Some(Diff::Added(right))
                }
            },

View on GitHub (pinned to a39730c5cd)