{"record":{"id":"9345cf8d773223f2","repo":"hashicorp/nomad","slug":"unable-to-move-to-q-alloc-dir-is-not-built","errorCode":null,"errorMessage":"unable to move to %q - alloc dir is not built","messagePattern":"unable to move to %q - alloc dir is not built","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"client/allocdir/alloc_dir.go","lineNumber":282,"sourceCode":"\t\t\t\t// the snapshotting side closed the connect\n\t\t\t\t// prematurely and won't try to use the tar\n\t\t\t\t// anyway.\n\t\t\t\ta.logger.Warn(\"snapshotting failed and unable to write error marker\", \"error\", writeErr)\n\t\t\t}\n\t\t\treturn fmt.Errorf(\"failed to snapshot %s: %w\", path, err)\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// 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)","sourceCodeStart":264,"sourceCodeEnd":300,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/client/allocdir/alloc_dir.go#L264-L300","documentation":"AllocDir.Move relocates a previous allocation's shared data and task-local directories into a new allocation directory. The struct enforces the invariant that Build() was called first: moving into an unbuilt alloc dir returns this error immediately. Previously this was an implicit assumption; now it is explicit validation.","triggerScenarios":"Calling Move (as the client runner does during allocation restoration/migration) on an AllocDir whose Build was skipped, failed earlier, or whose built flag was reset — e.g. after a Build error was swallowed upstream.","commonSituations":"Allocation restore paths where directory build failed silently; tests or custom code constructing AllocDir manually without Build; upgrades where build invariants changed.","solutions":["Ensure AllocDir.Build is called (and succeeds) before Move","Check logs for an earlier Build failure and fix its root cause (disk full, permissions)","Re-run the allocation restore so the client rebuilds the dir","In tests, call Build before Move"],"exampleFix":"// before\nallocDir.Move(oldAllocDir, tasks) // allocDir never built\n// after\nif err := allocDir.Build(); err != nil { return err }\nreturn allocDir.Move(oldAllocDir, tasks)","handlingStrategy":"validation","validationCode":"if !a.built { return errors.New(\"call Build() before Move()\") } // replicate the invariant in caller code","typeGuard":"func built(d *allocdir.AllocDir) bool { return d != nil } // ensure Build succeeded before Move; track build error explicitly","tryCatchPattern":"if err := allocDir.Move(old, tasks); err != nil && strings.Contains(err.Error(), \"alloc dir is not built\") {\n  return fmt.Errorf(\"restore failed: build alloc dir first: %w\", err)\n}","preventionTips":["Always call Build immediately after NewAllocDir and check its error","Never swallow Build errors upstream in restore paths","In tests, assert Build was invoked before Move"],"tags":["filesystem","lifecycle","allocation-migration"],"backgroundTag":"alloc-dir-not-built","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"}