GitoxideLabs/gitoxide · info

prior peek

Error message

prior peek

What it means

Same `next()` merge logic: after `peek_loose` returned `Some`, the loose iterator's `next()` must also return `Some`; `expect("prior peek")` enforces that the previously peeked loose entry still exists. A panic means peek and next disagreed for the loose iterator (git-dir or common-dir).

Solutions

  1. Avoid mutating refs (or running gc) concurrently with reference iteration, or hold appropriate locking
  2. Re-run the iteration; a one-off race resolves itself
  3. Check for background processes touching `.git/refs` during the operation
  4. If reproducible without concurrency, report a gix-ref bug
Defensive patterns

Strategy: retry

Try / catch

// Retry the whole iteration on panic, assuming a transient race
let refs = (0..3).find_map(|_| std::panic::catch_unwind(|| store.iter().collect::<Vec<_>>()).ok());

Prevention

When it happens

Trigger: Enumerating loose refs where `peek_loose` observed an entry but the inner `loose_iter(kind).next()` then returned `None` — caused by concurrent deletion of loose ref files between peek and next, or a broken iterator.

Common situations: Most plausible real-world cause is another process (e.g. `git gc`, a concurrent ref update) deleting the loose ref while the iteration was in progress; otherwise a gix-ref bug.

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 GitoxideLabs/gitoxide@e73179060b (2026-09-08). Data as JSON: /api/errors/9509dda2b4e142cc. Report an issue: GitHub.

Appendix: source

Thrown at gix-ref/src/store/file/overlay_iter.rs:165

                            Ordering::Greater => Some((r_cd, IterKind::Common)),
                        }
                    }
                },
                None => git_dir.peek().map(|r| (r, IterKind::Git)),
            }
        }
        match self.iter_packed.as_mut() {
            Some(packed_iter) => match (
                peek_loose(&mut self.iter_git_dir, self.iter_common_dir.as_mut()),
                packed_iter.peek(),
            ) {
                (None, None) => None,
                (None, Some(_)) | (Some(_), Some(Err(_))) => {
                    let res = packed_iter.next().expect("peeked value exists");
                    Some(self.convert_packed(res))
                }
                (Some((_, kind)), None) | (Some((Err(_), kind)), Some(_)) => {
                    let res = self.loose_iter(kind).next().expect("prior peek");
                    Some(self.convert_loose(res))
                }
                (Some((Ok((_, loose_name)), kind)), Some(Ok(packed))) => match loose_name.as_ref().cmp(packed.name) {
                    Ordering::Less => {
                        let res = self.loose_iter(kind).next().expect("prior peek");
                        Some(self.convert_loose(res))
                    }
                    Ordering::Equal => {
                        drop(packed_iter.next());
                        let res = self.loose_iter(kind).next().expect("prior peek");
                        Some(self.convert_loose(res))
                    }
                    Ordering::Greater => {
                        let res = packed_iter.next().expect("name retrieval configured");
                        Some(self.convert_packed(res))
                    }
                },
            },

View on GitHub (pinned to e73179060b)