{"record":{"id":"4bdfa826cdaf0239","repo":"hashicorp/nomad","slug":"error-moving-data-dir-w","errorCode":null,"errorMessage":"error moving data dir: %w","messagePattern":"error moving data dir: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"client/allocdir/alloc_dir.go","lineNumber":294,"sourceCode":"// Move other alloc directory's shared path and local dir to this alloc dir.\nfunc (a *AllocDir) Move(other Interface, tasks []*structs.Task) error {\n\ta.mu.RLock()\n\tif !a.built {\n\t\t// Enforce the invariant that Build is called before Move\n\t\ta.mu.RUnlock()\n\t\treturn fmt.Errorf(\"unable to move to %q - alloc dir is not built\", a.AllocDir)\n\t}\n\n\t// Moving is slow and only reads immutable fields, so unlock during heavy IO\n\ta.mu.RUnlock()\n\n\t// Move the data directory\n\totherDataDir := filepath.Join(other.ShareDirPath(), SharedDataDir)\n\tdataDir := filepath.Join(a.SharedDir, SharedDataDir)\n\tif fileInfo, err := os.Stat(otherDataDir); fileInfo != nil && err == nil {\n\t\tos.Remove(dataDir) // remove an empty data dir if it exists\n\t\tif err := os.Rename(otherDataDir, dataDir); err != nil {\n\t\t\treturn fmt.Errorf(\"error moving data dir: %w\", err)\n\t\t}\n\t}\n\n\t// Move the task directories\n\tfor _, task := range tasks {\n\t\totherTaskDir := filepath.Join(other.AllocDirPath(), task.Name)\n\t\totherTaskLocal := filepath.Join(otherTaskDir, TaskLocal)\n\n\t\tfileInfo, err := os.Stat(otherTaskLocal)\n\t\tif fileInfo != nil && err == nil {\n\t\t\t// TaskDirs haven't been built yet, so create it\n\t\t\tnewTaskDir := filepath.Join(a.AllocDir, task.Name)\n\t\t\tif err := os.MkdirAll(newTaskDir, fileMode777); err != nil {\n\t\t\t\treturn fmt.Errorf(\"error creating task %q dir: %w\", task.Name, err)\n\t\t\t}\n\t\t\tlocalDir := filepath.Join(newTaskDir, TaskLocal)\n\t\t\tos.Remove(localDir) // remove an empty local dir if it exists\n\t\t\tif err := os.Rename(otherTaskLocal, localDir); err != nil {","sourceCodeStart":276,"sourceCodeEnd":312,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/client/allocdir/alloc_dir.go#L276-L312","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\nif err := os.Rename(otherDataDir, dataDir); err != nil {\n  return fmt.Errorf(\"error moving data dir: %w\", err)\n}\n// after\nif err := os.Rename(otherDataDir, dataDir); err != nil {\n  if err2 := copyDir(otherDataDir, dataDir); err2 != nil {\n    return fmt.Errorf(\"error moving data dir: %w\", err)\n  }\n  os.RemoveAll(otherDataDir)\n}","handlingStrategy":"try-catch","validationCode":"od, err := os.Stat(otherDataDir)\nif err == nil && od != nil {\n  sameDev := syscall.Stat_t{ }\n  _ = syscall.Stat(otherDataDir, &sameDev) // compare Device with target's before rename\n}","typeGuard":null,"tryCatchPattern":"if err := allocDir.Move(other, tasks); err != nil && strings.Contains(err.Error(), \"error moving data dir\") {\n  // fall back to copy+delete or surface EXDEV/mount misconfiguration\n}","preventionTips":["Keep all alloc dirs under one filesystem root","Don't GC the source allocation during migration","Avoid read-only remounts during node maintenance windows"],"tags":["filesystem","rename","allocation-migration","exdev"],"backgroundTag":"cross-device-rename","analyzedSha":"482b49bf1aec006f089bcfc7e632d8f6ac303e5e","analyzedAt":"2026-09-04T07:54:14.808Z","contentChangedAt":"2026-09-04T07:54:14.808Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}