weaviate/weaviate · error

rename %s to %s

Error message

rename %s to %s

What it means

Commit() performs an atomic rename of the temp file to its final path; this is the point at which the new file becomes visible. If rename fails, the final file keeps its previous state and the temp file remains on disk. This wrapping includes both paths for easy diagnosis.

Source

Thrown at adapters/repos/db/vector/hnsw/compact/safe_file_writer.go:126

	// 1. Flush buffered writer
	if err := s.buffered.Flush(); err != nil {
		return errors.Wrap(err, "flush buffer")
	}

	// 2. Sync file to disk
	if err := s.file.Sync(); err != nil {
		return errors.Wrap(err, "sync file")
	}

	// 3. Close file (required before rename on some systems)
	if err := s.file.Close(); err != nil {
		return errors.Wrap(err, "close file")
	}
	s.closed = true

	// 4. Atomic rename
	if err := s.fs.Rename(s.tmpPath, s.finalPath); err != nil {
		return errors.Wrapf(err, "rename %s to %s", s.tmpPath, s.finalPath)
	}

	// 5. Sync parent directory
	if err := diskio.Fsync(filepath.Dir(s.finalPath)); err != nil {
		return errors.Wrap(err, "sync directory")
	}

	s.committed = true
	return nil
}

// Abort cleans up the temporary file without committing.
// Safe to call multiple times or after Commit.
func (s *SafeFileWriter) Abort() error {
	if s.committed {
		return nil
	}

View on GitHub (pinned to 75aa4b6d11)

Solutions

  1. Ensure temp and final paths resolve to the same filesystem (avoid symlinks/mounts splitting the path).
  2. Check directory write/execute permissions for the Weaviate process user.
  3. Don't run CleanupOrphanedTempFiles concurrently with active writes; it runs at load time — serialize operations.
  4. Investigate the underlying wrapped errno for the exact cause.

Example fix

// before
err := writer.Commit() // rename /data/x.condensed.tmp to /data/x.condensed: permission denied
// after
chown weaviate:weaviate /data
err := writer.Commit()
Defensive patterns

Strategy: validation

Validate before calling

// Ensure temp and final paths resolve to the same filesystem before writing
func sameDevice(a, b string) (bool, error) {
	var sa, sb unix.Stat_t
	if err := unix.Stat(filepath.Dir(a), &sa); err != nil { return false, err }
	if err := unix.Stat(filepath.Dir(b), &sb); err != nil { return false, err }
	return sa.Dev == sb.Dev, nil
}
// tmpPath := finalPath + suffix -> same dir, but verify no symlinks split devices:
ok, err := sameDevice(tmpPath, finalPath)

Try / catch

// Rename failure leaves final intact and temp present: safe to retry after fixing cause
if err := writer.Commit(); err != nil {
	if strings.Contains(err.Error(), "rename") {
		log.Warnf("commit rename failed, final file preserved: %v", err)
		return err // do not delete finalPath; fix perms/device and rerun
	}
	return err
}

Prevention

When it happens

Trigger: Commit() where fs.Rename(tmpPath, finalPath) fails: finalPath exists as a directory, cross-device rename (temp and final on different filesystems), permission denied on the directory, or the temp file was removed concurrently (e.g. by CleanupOrphanedTempFiles running in parallel).

Common situations: Data dir mounted across devices so tmp and final paths land on different filesystems (unusual, but possible with symlinked dirs); permission changes on the data directory; concurrent cleanup/garbage collection racing a commit.

Related errors


AI-assisted analysis of weaviate/weaviate@75aa4b6d11 (2026-09-04). Data as JSON: /api/errors/c563425800f61a26. Report an issue: GitHub.