{"record":{"id":"61a0be14a57c7e4a","repo":"hashicorp/nomad","slug":"error-building-alloc-dir-for-previous-alloc-q-w","errorCode":null,"errorMessage":"error building alloc dir for previous alloc %q: %w","messagePattern":"error building alloc dir for previous alloc %q: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"client/allocwatcher/alloc_watcher.go","lineNumber":525,"sourceCode":"\n\tif resp.Node == nil {\n\t\treturn \"\", fmt.Errorf(\"node %q not found\", nodeID)\n\t}\n\n\tscheme := \"http://\"\n\tif resp.Node.TLSEnabled {\n\t\tscheme = \"https://\"\n\t}\n\treturn scheme + resp.Node.HTTPAddr, nil\n}\n\n// migrate a remote alloc dir to local node. Caller is responsible for calling\n// Destroy on the returned allocdir if no error occurs.\nfunc (p *remotePrevAlloc) migrateAllocDir(ctx context.Context, nodeAddr string) (*allocdir.AllocDir, error) {\n\t// Create the previous alloc dir\n\tprevAllocDir := allocdir.NewAllocDir(p.logger, p.config.AllocDir, p.config.AllocMountsDir, p.prevAllocID)\n\tif err := prevAllocDir.Build(); err != nil {\n\t\treturn nil, fmt.Errorf(\"error building alloc dir for previous alloc %q: %w\", p.prevAllocID, err)\n\t}\n\n\t// Create an API client\n\tapiConfig := nomadapi.DefaultConfig()\n\tapiConfig.Address = nodeAddr\n\tapiConfig.TLSConfig = &nomadapi.TLSConfig{\n\t\tCACert:        p.config.TLSConfig.CAFile,\n\t\tClientCert:    p.config.TLSConfig.CertFile,\n\t\tClientKey:     p.config.TLSConfig.KeyFile,\n\t\tTLSServerName: fmt.Sprintf(\"client.%s.nomad\", p.config.Region),\n\t}\n\tapiClient, err := nomadapi.NewClient(apiConfig)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\turl := fmt.Sprintf(\"/v1/client/allocation/%v/snapshot\", p.prevAllocID)\n\tqo := &nomadapi.QueryOptions{AuthToken: p.migrateToken}","sourceCodeStart":507,"sourceCodeEnd":543,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/client/allocwatcher/alloc_watcher.go#L507-L543","documentation":"Nomad's remotePrevAlloc.migrateAllocDir creates a local directory for the previous allocation (via allocdir.NewAllocDir + Build()) before streaming the old node's snapshot into it. When Build() fails (e.g. the client's alloc/mounts root is unwritable or malformed), the error is wrapped as 'error building alloc dir for previous alloc %q: %w' and the migration aborts.","triggerScenarios":"Calling Migrate (via prevAllocWatcher) for a remote previous allocation when prevAllocDir.Build() fails: the client data directory (config.AllocDir or AllocMountsDir) does not exist or cannot be created, permissions deny mkdir, the filesystem is full or read-only, or the path collides with a non-directory file.","commonSituations":"Nomad client data_dir on a full disk or read-only volume; wrong permissions after running the agent as a different user; SELinux/AppArmor blocking directory creation; leftover file at the previous-alloc path blocking mkdir; misconfigured client { alloc_dir } in the agent config.","solutions":["Check the client's alloc_dir/data_dir exists, is a directory, and is writable by the Nomad agent user (ls -ld, touch test); fix permissions or path","Free disk space / remount the volume read-write if the filesystem is full or read-only","Remove any non-directory file or stale leftover at <alloc_dir>/<prevAllocID> then retry the allocation","Fix SELinux/AppArmor policies or run the agent with the intended user; then reschedule the allocation"],"exampleFix":"// before\nalloc_dir = \"/mnt/nomad\"  // mounted read-only or unwritable by nomad user\n// after\nalloc_dir = \"/opt/nomad/data\"  # chown nomad:nomad /opt/nomad/data && chmod 750","handlingStrategy":"validation","validationCode":"import \"os\"\n\nfunc allocDirWritable(dir string) error {\n\tif fi, err := os.Stat(dir); err != nil {\n\t\treturn err\n\t} else if !fi.IsDir() {\n\t\treturn fmt.Errorf(\"%s is not a directory\", dir)\n\t}\n\tf, err := os.CreateTemp(dir, \".writecheck*\")\n\tif err != nil {\n\t\treturn err\n\t}\n\tf.Close()\n\tos.Remove(f.Name())\n\treturn nil\n}","typeGuard":null,"tryCatchPattern":"prevAllocDir, err := migrateAllocDir(ctx, nodeAddr)\nif err != nil {\n\tif strings.Contains(err.Error(), \"error building alloc dir\") {\n\t\t// inspect unwrapped cause: check disk space/permissions on alloc_dir\n\t}\n\treturn err\n}","preventionTips":["Provision data_dir/alloc_dir with correct ownership for the nomad user and writable mounts","Monitor disk space and inode usage on client nodes","Keep alloc_dir on a persistent local filesystem, not a read-only or volatile mount","Clean stale allocation directories after node failures"],"tags":["filesystem","allocation-migration","nomad-client"],"backgroundTag":"mkdir-permission-denied","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"}