dgraph-io/dgraph · error

while closing file: %s

Error message

while closing file: %s

What it means

After a successful Sync, fileSyncer.Close closes the file descriptor and wraps any error as 'while closing file: <name>'. This is the file-descriptor close failure (e.g. EIO on close, EBADF), distinct from the sync failure at the same site.

Source

Thrown at worker/backup_handler.go:204

func (h *fileHandler) CreateDir(path string) error {
	path = h.JoinPath(path)
	if err := os.MkdirAll(path, 0755); err != nil {
		return errors.Errorf("Create path failed to create path %s, got error: %v", path, err)
	}
	return nil
}

type fileSyncer struct {
	fp *os.File
}

func (fs *fileSyncer) Write(p []byte) (n int, err error) { return fs.fp.Write(p) }
func (fs *fileSyncer) Close() error {
	if err := fs.fp.Sync(); err != nil {
		return errors.Wrapf(err, "while syncing file: %s", fs.fp.Name())
	}
	err := fs.fp.Close()
	return errors.Wrapf(err, "while closing file: %s", fs.fp.Name())
}

func (h *fileHandler) CreateFile(path string) (io.WriteCloser, error) {
	path = h.JoinPath(path)
	fp, err := os.Create(path)
	return &fileSyncer{fp}, errors.Wrapf(err, "File handler failed to create file %s", path)
}

func (h *fileHandler) Rename(src, dst string) error {
	src = h.JoinPath(src)
	dst = h.JoinPath(dst)
	return os.Rename(src, dst)
}

// pathExist checks if a path (file or dir) is found at target.
// Returns true if found, false otherwise.
func pathExist(path string) bool {
	_, err := os.Stat(path)

View on GitHub (pinned to 759e242be6)

Solutions

  1. Check the wrapped cause and whether the fd was already closed (double-Close race).
  2. Ensure callers close the writer exactly once (defer Close with a single owner).
  3. Check kernel logs for EIO on the device; replace failing hardware.
  4. Re-run the backup after fixing storage state.

Example fix

// before
err := fs.fp.Close()
return errors.Wrapf(err, "while closing file: %s", fs.fp.Name())
// after
if err := fs.fp.Close(); err != nil && !errors.Is(err, os.ErrClosed) {
    return errors.Wrapf(err, "while closing file: %s", fs.fp.Name())
}
return nil
Defensive patterns

Strategy: try-catch

Try / catch

err := writeBackup(...)
if err != nil {
    if strings.Contains(err.Error(), "while closing file") {
        log.Printf("backup close failed: %v — verify fd lifecycle (double close?)", err)
    }
    return err
}

Prevention

When it happens

Trigger: fs.fp.Close() returns an error: I/O error on close, fd already closed elsewhere (double Close), or descriptor issues during cleanup.

Common situations: Double-close of the same writer by caller and library code; failing disk reporting errors at close; NFS stale handles; use-after-timeout where another goroutine already closed the fd.

Related errors


AI-assisted analysis of dgraph-io/dgraph@759e242be6 (2026-09-01). Data as JSON: /api/errors/05ae5607e36db2e6. Report an issue: GitHub.