gastownhall/beads · error

failed to close temp file: %w

Error message

failed to close temp file: %w

What it means

atomicWriteFile explicitly closes the temp file after syncing; this wraps a tmp.Close failure. A failed close means buffered data may not have reached disk reliably, so the temp file is discarded and the destination untouched.

Source

Thrown at cmd/bd/backup_export.go:116

	tmp, err := os.CreateTemp(dir, ".backup-tmp-*")
	if err != nil {
		return fmt.Errorf("failed to create temp file: %w", err)
	}
	tmpPath := tmp.Name()

	if _, err := tmp.Write(data); err != nil {
		_ = tmp.Close()
		_ = os.Remove(tmpPath)
		return fmt.Errorf("failed to write temp file: %w", err)
	}
	if err := tmp.Sync(); err != nil {
		_ = tmp.Close()
		_ = os.Remove(tmpPath)
		return fmt.Errorf("failed to sync temp file: %w", err)
	}
	if err := tmp.Close(); err != nil {
		_ = os.Remove(tmpPath)
		return fmt.Errorf("failed to close temp file: %w", err)
	}
	if err := os.Rename(tmpPath, path); err != nil {
		_ = os.Remove(tmpPath)
		return fmt.Errorf("failed to rename temp file: %w", err)
	}
	return nil
}

// runBackupExport performs a Dolt-native backup to .beads/backup/.
// Returns the updated state.
func runBackupExport(ctx context.Context, force bool) (*backupState, error) {
	dir, err := backupDir()
	if err != nil {
		return nil, err
	}

	state, err := loadBackupState(dir)
	if err != nil {

View on GitHub (pinned to 71377f2769)

Solutions

  1. Check open file descriptor limits and usage: ulimit -n; lsof | wc -l.
  2. Raise the limit if exhausted (ulimit -n 4096 or systemd LimitNOFILE) or fix leaking processes.
  3. Retry the command — atomic write guarantees the previous backup_state.json is intact.
  4. If persistent, check for system-wide file table exhaustion (fs.file-max).

Example fix

// shell
ulimit -n 4096 && bd sync
Defensive patterns

Strategy: validation

Validate before calling

// fd exhaustion is the usual cause; check headroom before running
count, _ := filepath.Glob("/proc/self/fd/*")
if len(count) > 900 { // typical soft limit 1024
    return errors.New("too many open fds before bd operation")
}

Try / catch

if err := saveBackupState(dir, state); err != nil {
    if strings.Contains(err.Error(), "close temp file") {
        log.Printf("fd pressure suspected; raise ulimit -n and retry: %v", err)
        return err
    }
    return err
}

Prevention

When it happens

Trigger: tmp.Close() returns non-nil: file descriptor exhaustion (EMFILE), or a deferred write error surfaced at close.

Common situations: Process hit its open-file limit (ulimit -n) due to leaked descriptors; kernel memory pressure preventing flush.

Related errors


AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30). Data as JSON: /api/errors/abd04caf73d86afc. Report an issue: GitHub.