gastownhall/beads · error
atomicfile: close: %w
Error message
atomicfile: close: %w
What it means
After chmod and sync succeed, Writer.Close calls f.Close(). If closing the file descriptor reports an error (e.g. deferred write errors surfaced at close, or the fd was already closed), the temp file is removed and this wrapped error is returned; the target stays intact.
Source
Thrown at internal/atomicfile/atomicfile.go:90
}
w.done = true
// Ensure permissions before rename — CreateTemp uses 0600 by default.
if err := w.f.Chmod(w.perm); err != nil {
_ = w.f.Close()
_ = os.Remove(w.f.Name())
return fmt.Errorf("atomicfile: chmod: %w", err)
}
if err := w.f.Sync(); err != nil {
_ = w.f.Close()
_ = os.Remove(w.f.Name())
return fmt.Errorf("atomicfile: sync: %w", err)
}
if err := w.f.Close(); err != nil {
_ = os.Remove(w.f.Name())
return fmt.Errorf("atomicfile: close: %w", err)
}
if err := os.Rename(w.f.Name(), w.target); err != nil {
_ = os.Remove(w.f.Name())
return fmt.Errorf("atomicfile: rename: %w", err)
}
return nil
}
// Abort discards the temp file without renaming. The target is untouched.
// Safe to call multiple times or after Close.
func (w *Writer) Abort() error {
if w.done {
return nil
}
w.done = true
_ = w.f.Close()View on GitHub (pinned to 71377f2769)
Solutions
- Call Close exactly once per Writer (use Abort for the discard path instead)
- Check for 'file already closed' in the wrapped error to find a double-close bug
- If the error indicates an I/O problem, retry the whole Create/Close sequence
Example fix
// before
w.Abort()
w.Close() // double-close -> "atomicfile: close"
// after
if err := w.Close(); err != nil { /* handle */ } // only one finalizer path Defensive patterns
Strategy: try-catch
Try / catch
if err := w.Close(); err != nil {
if strings.Contains(err.Error(), "file already closed") {
log.Printf("double Close detected: %v", err)
}
return err
} Prevention
- Have exactly one ownership path that closes the Writer
- Never close w.f directly; use Close/Abort
- Audit code paths where both Abort and Close could run
When it happens
Trigger: Calling Close twice on the same Writer, or the OS returning an error at close time (delayed I/O error, fd exhaustion artifacts).
Common situations: Control-flow bugs where Abort and Close are both called, or code paths that close the underlying file independently of the Writer.
Related errors
- atomicfile: create temp: %w
- failed to read backup state: %w
- failed to create temp file: %w
- failed to write temp file: %w
- failed to sync temp file: %w
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/d6a66c8f95d54038.
Report an issue: GitHub.