hashicorp/nomad · error

failed to resolve alloc directory: %w

Error message

failed to resolve alloc directory: %w

What it means

AllocDir.sanitizePath() resolves the alloc directory via filepath.EvalSymlinks before validating client-supplied paths. If the alloc dir cannot be resolved (it does not exist or a symlink component is broken/unreadable), this wrapped error is returned.

Source

Thrown at client/allocdir/alloc_dir.go:418

			Name:     info.Name(),
			IsDir:    info.IsDir(),
			Size:     info.Size(),
			FileMode: info.Mode().String(),
			ModTime:  info.ModTime(),
		}
	}
	return files, err
}

// sanitizePath checks that the path does not escape the alloc directory,
// does not read into the secrets or private directories and returns an absolute
// path of the provided path.
func (a *AllocDir) sanitizePath(path string) (string, error) {
	// In some non linux systmes, directories like /var and /tmp resolve to
	// /private/var and /private/tmp.
	resolvedAllocDir, err := filepath.EvalSymlinks(a.AllocDir)
	if err != nil {
		return "", fmt.Errorf("failed to resolve alloc directory: %w", err)
	}

	requestedPath, err := filepath.Abs(filepath.Join(resolvedAllocDir, path))
	if err != nil {
		return "", fmt.Errorf("failed to resolve requested path: %w", err)
	}

	if err := escapingfs.ChildEscapesParentDir(resolvedAllocDir, requestedPath); err != nil {
		return "", fmt.Errorf("path escapes the alloc directory")
	}

	a.mu.RLock()
	defer a.mu.RUnlock()

	// Check it does not access the secrets or private directories
	for _, taskDir := range a.TaskDirs {
		rps := strings.ReplaceAll(requestedPath, "/Secrets", "/secrets")
		if err := escapingfs.ChildEscapesParentDir(taskDir.SecretsDir, rps); err == nil {

View on GitHub (pinned to 482b49bf1a)

Solutions

  1. Verify the alloc dir still exists before issuing API calls; avoid racing with Destroy/GC
  2. Check that the alloc dir path and all symlink components are readable and resolvable
  3. Fix or remove dangling symlinks in the path
  4. Re-create the alloc dir via Build() if it was removed unintentionally

Example fix

// before
f, err := allocDir.ReadAt(path, offset)
// after
if _, err := os.Stat(allocDir.AllocDir); err != nil {
    return nil, fmt.Errorf("alloc dir gone: %w", err)
}
f, err := allocDir.ReadAt(path, offset)
Defensive patterns

Strategy: validation

Validate before calling

if _, err := filepath.EvalSymlinks(allocDir.AllocDir); err != nil {
    return fmt.Errorf("alloc dir unavailable: %w", err)
}

Try / catch

out, err := allocDir.List(relPath)
if err != nil && strings.Contains(err.Error(), "failed to resolve alloc directory") {
    // alloc dir destroyed/GC'd: stop polling instead of retrying forever
    return ErrAllocDirGone
}

Prevention

When it happens

Trigger: Calling List, Stat, ReadAt, BlockUntilExists or ChangeEvents when filepath.EvalSymlinks(a.AllocDir) fails — typically because the alloc dir no longer exists (destroyed) or contains an unresolvable symlink.

Common situations: Filesystem API calls racing with allocation GC/Destroy which removed the alloc dir; host-dir paths that are dangling symlinks; permission issues preventing traversal of the alloc dir path.

Related errors


AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04). Data as JSON: /api/errors/64a59cd56f312747. Report an issue: GitHub.