GitoxideLabs/gitoxide · error
BUG: must consume and drop entry before getting the next one
Error message
BUG: must consume and drop entry before getting the next one
What it means
This panic comes from an assertion in gix_worktree_stream::Stream::next_entry(). The stream keeps the previous Entry's path buffer alive until the caller drops the entry, because Entry borrows internal stream state. Calling next_entry() again while the previous Entry is still alive would create two live borrows sharing the same mutable buffer, so the library panics by design.
Solutions
- Ensure the previously returned Entry is dropped before calling next_entry() again (let it go out of scope or call std::mem::drop(entry)).
- Restructure the loop so each entry is fully processed and dropped before fetching the next one.
- If you need to keep multiple entries, clone the data you need (e.g. the path or bytes) instead of holding the Entry itself.
Example fix
// before let e1 = stream.next_entry()?; let e2 = stream.next_entry()?; // panics: e1 still alive // after let e1 = stream.next_entry()?; let path = e1.path().to_owned(); drop(e1); let e2 = stream.next_entry()?;
Defensive patterns
Strategy: validation
Validate before calling
if self.path_buf.is_some() {
// previous entry still borrowed: drop it before fetching the next
drop(prev_entry);
}
let next = stream.next_entry()?; Prevention
- Scope each Entry in its own block: { let e = stream.next_entry()?; process(e); }
- Never store Entry values across next_entry() calls; clone needed data instead.
- Remember Entry borrows the stream - keep the borrow short-lived.
When it happens
Trigger: Calling stream.next_entry() twice without letting the returned Entry be dropped first, e.g. storing the Entry in a variable that is still in scope during the second call, or holding entries in a collection while iterating.
Common situations: Collecting multiple entries into a Vec in a loop; storing a reference into the Entry while advancing; refactoring from iterator-style code where items are kept alive; forgetting that Entry borrows &mut the stream.
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
- ' ' is not a valid configuration key
- Cannot use iter_v1() on index of type
- Cannot use iter_v2() on index of type
- BUG: tries to obtain object id from symbolic target
- BUG: expected peeled reference target but found symbolic one
AI-assisted analysis of GitoxideLabs/gitoxide@e73179060b (2026-09-08).
Data as JSON: /api/errors/83c555971a7df289.
Report an issue: GitHub.
Appendix: source
Thrown at gix-worktree-stream/src/entry.rs:19
use std::{
io::{ErrorKind, Read},
path::PathBuf,
};
use gix_error::ErrorExt;
use gix_object::bstr::BStr;
use crate::{Entry, Stream, protocol};
/// The error returned by [`next_entry()`][Stream::next_entry()].
pub type Error = gix_error::Exn<gix_error::Message>;
impl Stream {
/// Access the next entry of the stream or `None` if there is nothing more to read.
pub fn next_entry(&mut self) -> Result<Option<Entry<'_>>, Error> {
assert!(
self.path_buf.is_some(),
"BUG: must consume and drop entry before getting the next one"
);
self.extra_entries.take();
let res = protocol::read_entry_info(
&mut self.read,
self.path_buf.as_mut().expect("set while producing an entry"),
);
match res {
Ok((remaining, mode, id)) => {
if let Some(err) = self.err.lock().take() {
return Err(err);
}
Ok(Some(Entry {
path_buf: self.path_buf.take(),
parent: self,
id,
mode,
remaining,
}))View on GitHub (pinned to e73179060b)