GitoxideLabs/gitoxide · info
peeked value exists
Error message
peeked value exists
What it means
In `OverlayIter::next`, the packed iterator was `peek`ed and returned `Some`, so the following `next()` must also return `Some`; `expect("peeked value exists")` enforces that. A panic indicates the underlying packed-refs iterator misbehaved (peek and next disagree) or the iterator was mutated concurrently.
Solutions
- Ensure the iterator is not shared or mutated across threads (wrap in a Mutex if needed)
- Re-run the iteration from a fresh `store.iter()`; a transient state may explain it
- Verify `packed-refs` integrity and regenerate it (e.g. `git pack-refs --all`)
- If reproducible on a fresh iterator, report a gix-ref bug with the packed-refs contents
Defensive patterns
Strategy: retry
Try / catch
// Wrap iteration in retry against a fresh iterator
for _ in 0..3 { if let Ok(refs) = std::panic::catch_unwind(|| store.iter().collect::<Vec<_>>()) { break; } } Prevention
- Never share or mutate iterators across threads
- Iterate over a snapshot: collect refs once, then process
- Avoid concurrent `git pack-refs` during reads
- Regenerate packed-refs if it looks inconsistent
When it happens
Trigger: Iterating references over a repository with a `packed-refs` file where `Peekable::peek` succeeded but the subsequent `next()` returned `None` — only possible with a broken/concurrently-modified iterator implementation.
Common situations: Effectively unreachable; if observed, suspect concurrent modification of the iterator, custom unsafe wrapper code, or a gix-ref/packed-refs bug. Normal single-threaded iteration of `store.iter()` never triggers it.
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
- name retrieval configured
- caller knows there is a common iter
- prior peek
- this one only happens on iteration creation
- BUG: packed refs cannot contain symbolic refs, catch that…
AI-assisted analysis of GitoxideLabs/gitoxide@e73179060b (2026-09-08).
Data as JSON: /api/errors/0d2b08450b5b84e5.
Report an issue: GitHub.
Appendix: source
Thrown at gix-ref/src/store/file/overlay_iter.rs:161
(Some(r_gitdir @ Ok((_, git_dir_name))), Some(r_cd @ Ok((_, common_dir_name)))) => {
match git_dir_name.cmp(common_dir_name) {
Ordering::Less => Some((r_gitdir, IterKind::Git)),
Ordering::Equal => Some((r_gitdir, IterKind::GitAndConsumeCommon)),
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");View on GitHub (pinned to e73179060b)