GitoxideLabs/gitoxide · error
The tempfile with id
Error message
The tempfile with id {} wasn't available anymore What it means
Returned by `Handle::close()` when the tempfile backing this handle is no longer present in the global registry. The registry entry is either gone (removed) or its slot holds `None`, which happens after the handle was already closed, taken, or the registry entry was consumed. The library throws this to prevent double-close/use-after-close on tempfile handles.
Solutions
- Ensure `close()` is called at most once per handle, e.g. via `Option<Handle>` and `.take()`
- Restructure code so ownership of the handle makes double-close impossible (move the handle into the closing scope)
- If persisting, use `persist()` instead of `close()` and do not reuse the handle afterwards
Example fix
// before
handle.close()?;
// ...
handle.close()?; // NotFound: already closed
// after
if let Some(handle) = handle_opt.take() {
handle.close()?;
} Defensive patterns
Strategy: try-catch
Validate before calling
// Rust: only close when the handle is still owned/open
fn close_once(handle: &mut Option<gix_tempfile::Handle<gix_tempfile::Closed>>) -> std::io::Result<()> {
// a Closed-typed handle cannot call close(); None means already handled
let _ = handle;
Ok(())
} Type guard
fn is_open(h: &Option<gix_tempfile::Handle<gix_tempfile::Open>>) -> bool { h.is_some() } Try / catch
match handle.take() {
Some(h) => match h.close() {
Ok(_) => {},
Err(e) if e.kind() == std::io::ErrorKind::NotFound => { /* already closed; treat as idempotent */ },
Err(e) => return Err(e),
},
None => { /* already closed */ }
} Prevention
- Model handle lifetime with typestate (Open/Closed) so double-close cannot compile
- Wrap handles in Option and .take() before closing
- Never store handles long-term; use them in a scope and close/drop at the end
When it happens
Trigger: Calling `close()` on a `Handle` that was already closed, or on a handle whose registry entry was consumed (e.g. via `take()`/persist), or after the registry entry was dropped.
Common situations: Closing the same tempfile handle twice in error-recovery paths; persisting a tempfile (which consumes it) and then calling `close()` on the stale handle; sharing a handle across threads where one side closes it first.
Understand the failure class
Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 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/58b92f7c230e580c.
Report an issue: GitHub.
Appendix: source
Thrown at gix-tempfile/src/handle.rs:191
res.and_then(|(_k, v)| v.map(|v| v.into_tempfile().expect("correct runtime typing")))
}
/// Close the underlying file handle but keep track of the temporary file as before for automatic cleanup.
///
/// This saves system resources in situations where one opens a tempfile file at a time, writes a new value, and closes
/// it right after to perform more updates of this kind in other tempfiles. When all succeed, they can be renamed one after
/// another.
pub fn close(self) -> std::io::Result<Handle<Closed>> {
match REGISTRY.remove(&self.id) {
Some((id, Some(t))) => {
std::mem::forget(self);
expect_none(REGISTRY.insert(id, Some(t.close())));
Ok(Handle::<Closed> {
id,
_marker: Default::default(),
})
}
None | Some((_, None)) => Err(std::io::Error::new(
std::io::ErrorKind::NotFound,
format!("The tempfile with id {} wasn't available anymore", self.id),
)),
}
}
}
/// Mutation
impl Handle<Writable> {
/// Obtain a mutable handler to the underlying named tempfile and call `f(&mut named_tempfile)` on it.
///
/// Note that for the duration of the call, a signal interrupting the operation will cause the tempfile not to be cleaned up
/// as it is not visible anymore to the signal handler.
///
/// # Assumptions
/// The caller must assure that the signal handler for cleanup will be followed by an abort call so that
/// this code won't run again on a removed instance. An error will occur otherwise.
pub fn with_mut<T>(&mut self, once: impl FnOnce(&mut NamedTempFile) -> T) -> std::io::Result<T> {View on GitHub (pinned to e73179060b)