{"record":{"id":"83c555971a7df289","repo":"GitoxideLabs/gitoxide","slug":"bug-must-consume-and-drop-entry-before-getting-th","errorCode":null,"errorMessage":"BUG: must consume and drop entry before getting the next one","messagePattern":"BUG: must consume and drop entry before getting the next one","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"gix-worktree-stream/src/entry.rs","lineNumber":19,"sourceCode":"use std::{\n    io::{ErrorKind, Read},\n    path::PathBuf,\n};\n\nuse gix_error::ErrorExt;\nuse gix_object::bstr::BStr;\n\nuse crate::{Entry, Stream, protocol};\n\n/// The error returned by [`next_entry()`][Stream::next_entry()].\npub type Error = gix_error::Exn<gix_error::Message>;\n\nimpl Stream {\n    /// Access the next entry of the stream or `None` if there is nothing more to read.\n    pub fn next_entry(&mut self) -> Result<Option<Entry<'_>>, Error> {\n        assert!(\n            self.path_buf.is_some(),\n            \"BUG: must consume and drop entry before getting the next one\"\n        );\n        self.extra_entries.take();\n        let res = protocol::read_entry_info(\n            &mut self.read,\n            self.path_buf.as_mut().expect(\"set while producing an entry\"),\n        );\n        match res {\n            Ok((remaining, mode, id)) => {\n                if let Some(err) = self.err.lock().take() {\n                    return Err(err);\n                }\n                Ok(Some(Entry {\n                    path_buf: self.path_buf.take(),\n                    parent: self,\n                    id,\n                    mode,\n                    remaining,\n                }))","sourceCodeStart":1,"sourceCodeEnd":37,"githubUrl":"https://github.com/GitoxideLabs/gitoxide/blob/e73179060badf27222d790981fac3f84c1830a7e/gix-worktree-stream/src/entry.rs#L1-L37","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nlet e1 = stream.next_entry()?;\nlet e2 = stream.next_entry()?; // panics: e1 still alive\n// after\nlet e1 = stream.next_entry()?;\nlet path = e1.path().to_owned();\ndrop(e1);\nlet e2 = stream.next_entry()?;","handlingStrategy":"validation","validationCode":"if self.path_buf.is_some() {\n    // previous entry still borrowed: drop it before fetching the next\n    drop(prev_entry);\n}\nlet next = stream.next_entry()?;","typeGuard":null,"tryCatchPattern":null,"preventionTips":["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."],"tags":["rust","panic","borrow-rules","stream-iteration"],"backgroundTag":"internal-invariant-violation","analyzedSha":"e73179060badf27222d790981fac3f84c1830a7e","analyzedAt":"2026-09-08T11:26:50.865Z","contentChangedAt":"2026-09-08T11:26:50.865Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}