pola-rs/polars · error

itertools: .zip_eq() reached end of one iterator before the…

Error message

itertools: .zip_eq() reached end of one iterator before the other

What it means

Polars' ZipEq iterator panics when one of the two zipped iterators is exhausted before the other, i.e. they have unequal lengths. Unlike std::iter::zip (which silently stops at the shorter iterator), zip_eq asserts both sides have equal length, since unequal lengths indicate a broken invariant in the calling code.

Solutions

  1. Identify the two iterators being zipped and verify their lengths are equal before iteration
  2. If unequal lengths are legitimate, use std::iter::zip instead of zip_eq and handle the short side
  3. Report/fix the upstream invariant violation if this comes from within Polars itself (often a bug — check the issue tracker)

Example fix

// before
assert_eq!(a.len(), b.len(), "zip_eq inputs differ");
let pairs: Vec<_> = a.iter().zip_eq(b.iter()).collect();
// after
if a.len() != b.len() {
    let pairs: Vec<_> = a.iter().zip(b.iter()).collect(); // tolerate short side
} else {
    let pairs: Vec<_> = a.iter().zip_eq(b.iter()).collect();
}
Defensive patterns

Strategy: type-guard

Validate before calling

// Rust: assert equal lengths before zipping
assert_eq!(a.len(), b.len(), "zip_eq requires equal-length iterators");

Type guard

fn equal_len<A, B>(a: &[A], b: &[B]) -> bool { a.len() == b.len() }

Prevention

When it happens

Trigger: Any use of zip_eq (from polars-utils' itertools) where the two iterators produce different numbers of elements — e.g. zipping columns of a frame that have different lengths, or chunk lists built inconsistently.

Common situations: Internal invariant bugs where two collections are assumed parallel but constructed differently; plugin/extension code zipping field lists against array lists after a schema change; version-skew between polars crates.

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 pola-rs/polars@fe841f959e (2026-09-18). Data as JSON: /api/errors/2d8c1c15087d0252. Report an issue: GitHub.

Appendix: source

Thrown at crates/polars-utils/src/itertools/zip_eq.rs:20

/// An iterator which iterates two other iterators simultaneously
/// and panic if they have different lengths.
#[derive(Clone, Debug)]
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
pub struct ZipEq<I, J> {
    a: I,
    b: J,
}

impl<I: Iterator, J: Iterator> Iterator for ZipEq<I, J> {
    type Item = (I::Item, J::Item);

    fn next(&mut self) -> Option<Self::Item> {
        match (self.a.next(), self.b.next()) {
            (None, None) => None,
            (Some(a), Some(b)) => Some((a, b)),
            (None, Some(_)) | (Some(_), None) => {
                panic!("itertools: .zip_eq() reached end of one iterator before the other")
            },
        }
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        let (a_lower, a_upper) = self.a.size_hint();
        let (b_lower, b_upper) = self.b.size_hint();
        let lower = cmp::min(a_lower, b_lower);
        let upper = match (a_upper, b_upper) {
            (Some(u1), Some(u2)) => Some(cmp::min(u1, u2)),
            _ => a_upper.or(b_upper),
        };
        (lower, upper)
    }
}

impl<I: ExactSizeIterator, J: ExactSizeIterator> ExactSizeIterator for ZipEq<I, J> {}

View on GitHub (pinned to fe841f959e)