{"record":{"id":"ad1a650b0236b088","repo":"hashicorp/nomad","slug":"failed-to-remove-alloc-dir-q-w","errorCode":null,"errorMessage":"failed to remove alloc dir %q: %w","messagePattern":"failed to remove alloc dir %q: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"client/allocdir/alloc_dir.go","lineNumber":330,"sourceCode":"\t\t\tif err := os.Rename(otherTaskLocal, localDir); err != nil {\n\t\t\t\treturn fmt.Errorf(\"error moving task %q local dir: %w\", task.Name, err)\n\t\t\t}\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// Destroy tears down previously build directory structure.\nfunc (a *AllocDir) Destroy() error {\n\t// Unmount all mounted shared alloc dirs.\n\tmErr := new(multierror.Error)\n\tif err := a.UnmountAll(); err != nil {\n\t\tmErr = multierror.Append(mErr, err)\n\t}\n\n\tif err := os.RemoveAll(a.AllocDir); err != nil {\n\t\tmErr = multierror.Append(mErr, fmt.Errorf(\"failed to remove alloc dir %q: %w\", a.AllocDir, err))\n\t}\n\n\t// Unset built since the alloc dir has been destroyed.\n\ta.mu.Lock()\n\ta.built = false\n\ta.mu.Unlock()\n\treturn mErr.ErrorOrNil()\n}\n\n// UnmountAll linked/mounted directories in task dirs.\nfunc (a *AllocDir) UnmountAll() error {\n\ta.mu.RLock()\n\tdefer a.mu.RUnlock()\n\n\tmErr := new(multierror.Error)\n\tfor _, dir := range a.TaskDirs {\n\t\tif err := dir.Unmount(); err != nil {\n\t\t\tmErr = multierror.Append(mErr, err)","sourceCodeStart":312,"sourceCodeEnd":348,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/client/allocdir/alloc_dir.go#L312-L348","documentation":"AllocDir.Destroy() removes the whole allocation directory tree with os.RemoveAll. If that syscall fails for any reason, the underlying OS error is wrapped with the alloc dir path into this message and appended to a multierror (along with any UnmountAll failure) returned by Destroy.","triggerScenarios":"Calling AllocDir.Destroy() when os.RemoveAll(a.AllocDir) fails: files inside the tree still held open or mounted by a running task, read-only filesystem, or permission denied on a subdirectory owned by another user.","commonSituations":"Tearing down an allocation whose tasks or other processes still have mounts/files open in the alloc dir; running the Nomad client with insufficient privileges; leftover bind mounts from leaked task processes preventing removal.","solutions":["Ensure all tasks are stopped and UnmountAll has unmounted every mount before Destroy","Check for leaked processes holding mounts in the alloc dir (lsof / findmnt) and kill or unmount them","Verify the nomad user has write permission on the alloc dir and its parent and the filesystem is not read-only","Manually remove the leftover directory (rm -rf) and investigate the wrapped OS error for the root cause"],"exampleFix":"// before\nif err := allocDir.Destroy(); err != nil {\n    logger.Error(\"destroy failed\", \"err\", err)\n}\n// after\nif err := allocDir.UnmountAll(); err != nil {\n    logger.Warn(\"unmount leaked mounts\", \"err\", err)\n}\nif err := allocDir.Destroy(); err != nil {\n    logger.Error(\"destroy failed\", \"err\", err)\n}","handlingStrategy":"try-catch","validationCode":"if _, err := os.Stat(allocDir.AllocDir); err == nil {\n    if err := allocDir.UnmountAll(); err != nil {\n        logger.Warn(\"unmount incomplete\", \"err\", err)\n    }\n}","typeGuard":null,"tryCatchPattern":"if err := allocDir.Destroy(); err != nil {\n    var pathErr *os.PathError\n    if errors.As(err, &pathErr) && errors.Is(pathErr.Err, unix.EBUSY) {\n        // leaked mount: find and unmount, then retry Destroy\n    }\n    logger.Error(\"alloc dir destroy failed\", \"err\", err)\n}","preventionTips":["Always stop tasks and wait for process exit before Destroy","Call UnmountAll first and log its errors separately","Monitor for leftover mounts under the client alloc dir","Run the nomad agent with adequate filesystem privileges"],"tags":["filesystem","cleanup","nomad-client"],"backgroundTag":"directory-removal-failed","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"}