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
- Ensure temp and final paths resolve to the same filesystem (avoid symlinks/mounts splitting the path).
- Check directory write/execute permissions for the Weaviate process user.
- Don't run CleanupOrphanedTempFiles concurrently with active writes; it runs at load time — serialize operations.
- 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
- Never symlink or bind-mount parts of the shard directory path across devices.
- Keep directory permissions consistent for the service user.
- Don't run temp-file cleanup concurrently with active compaction/snapshot writes.
- Check the wrapped errno in the message to distinguish EACCES/EEXIST/EXDEV.
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
- rename %q to %q: %w
- create backup staging dir: %w
- stat shard dir: %w
- create staging subdir for inactive shard %s file %s: %w
- stat objects bucket dir for shard %s: %w
AI-assisted analysis of weaviate/weaviate@75aa4b6d11 (2026-09-04).
Data as JSON: /api/errors/c563425800f61a26.
Report an issue: GitHub.