hashicorp/nomad · error
error moving data dir: %w
Error message
error moving data dir: %w
What it means
Move renames the previous allocation's SharedDataDir into the new allocation dir with os.Rename. If the rename fails (cross-device filesystems, permissions, source vanished), the error is wrapped as 'error moving data dir'. Rename requires both paths on the same mounted filesystem.
Source
Thrown at client/allocdir/alloc_dir.go:294
// Move other alloc directory's shared path and local dir to this alloc dir.
func (a *AllocDir) Move(other Interface, tasks []*structs.Task) error {
a.mu.RLock()
if !a.built {
// Enforce the invariant that Build is called before Move
a.mu.RUnlock()
return fmt.Errorf("unable to move to %q - alloc dir is not built", a.AllocDir)
}
// Moving is slow and only reads immutable fields, so unlock during heavy IO
a.mu.RUnlock()
// Move the data directory
otherDataDir := filepath.Join(other.ShareDirPath(), SharedDataDir)
dataDir := filepath.Join(a.SharedDir, SharedDataDir)
if fileInfo, err := os.Stat(otherDataDir); fileInfo != nil && err == nil {
os.Remove(dataDir) // remove an empty data dir if it exists
if err := os.Rename(otherDataDir, dataDir); err != nil {
return fmt.Errorf("error moving data dir: %w", err)
}
}
// Move the task directories
for _, task := range tasks {
otherTaskDir := filepath.Join(other.AllocDirPath(), task.Name)
otherTaskLocal := filepath.Join(otherTaskDir, TaskLocal)
fileInfo, err := os.Stat(otherTaskLocal)
if fileInfo != nil && err == nil {
// TaskDirs haven't been built yet, so create it
newTaskDir := filepath.Join(a.AllocDir, task.Name)
if err := os.MkdirAll(newTaskDir, fileMode777); err != nil {
return fmt.Errorf("error creating task %q dir: %w", task.Name, err)
}
localDir := filepath.Join(newTaskDir, TaskLocal)
os.Remove(localDir) // remove an empty local dir if it exists
if err := os.Rename(otherTaskLocal, localDir); err != nil {View on GitHub (pinned to 482b49bf1a)
Solutions
- Ensure old and new alloc dirs are on the same filesystem/device
- Check directory permissions on both alloc dirs
- Verify the source data dir still exists (not GC'd) at migration time
- Copy-then-delete as a fallback when cross-device moves are unavoidable
Example fix
// before
if err := os.Rename(otherDataDir, dataDir); err != nil {
return fmt.Errorf("error moving data dir: %w", err)
}
// after
if err := os.Rename(otherDataDir, dataDir); err != nil {
if err2 := copyDir(otherDataDir, dataDir); err2 != nil {
return fmt.Errorf("error moving data dir: %w", err)
}
os.RemoveAll(otherDataDir)
} Defensive patterns
Strategy: try-catch
Validate before calling
od, err := os.Stat(otherDataDir)
if err == nil && od != nil {
sameDev := syscall.Stat_t{ }
_ = syscall.Stat(otherDataDir, &sameDev) // compare Device with target's before rename
} Try / catch
if err := allocDir.Move(other, tasks); err != nil && strings.Contains(err.Error(), "error moving data dir") {
// fall back to copy+delete or surface EXDEV/mount misconfiguration
} Prevention
- Keep all alloc dirs under one filesystem root
- Don't GC the source allocation during migration
- Avoid read-only remounts during node maintenance windows
When it happens
Trigger: os.Rename of otherDataDir fails — source alloc dir on a different device/mount than the target, permission denial, or the source data dir removed concurrently by GC.
Common situations: Alloc dirs spanned across volumes/bind-mounts (host volume layouts); node filesystem remounts read-only; GC racing with migration; permission mismatches after node re-provisioning.
Related errors
- error moving task %q local dir: %w
- unable to move to %q - alloc dir is not built
- error creating task %q dir: %w
- error building alloc dir for previous alloc %q: %w
- cannot install new nomad binary - %s
AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04).
Data as JSON: /api/errors/4bdfa826cdaf0239.
Report an issue: GitHub.