hashicorp/nomad · error

error creating symlink: %w

Error message

error creating symlink: %w

What it means

When extracting a symlink entry from the alloc dir tar archive, os.Symlink(hdr.Linkname, dest/hdr.Name) failed. This can happen if the target path already exists, the parent directory is missing, or the filesystem forbids symlinks.

Source

Thrown at client/allocwatcher/alloc_watcher.go:630

		}

		// If the header is for a directory we create the directory
		if hdr.Typeflag == tar.TypeDir {
			name := filepath.Join(dest, hdr.Name)
			os.MkdirAll(name, os.FileMode(hdr.Mode))

			// Can't change owner if not root or on Windows.
			if euid == 0 {
				if err := os.Chown(name, hdr.Uid, hdr.Gid); err != nil {
					return fmt.Errorf("error chowning directory %w", err)
				}
			}
			continue
		}
		// If the header is for a symlink we create the symlink
		if hdr.Typeflag == tar.TypeSymlink {
			if err = os.Symlink(hdr.Linkname, filepath.Join(dest, hdr.Name)); err != nil {
				return fmt.Errorf("error creating symlink: %w", err)
			}

			for _, path := range []string{hdr.Name, hdr.Linkname} {
				if escapes, err := escapingfs.PathEscapesAllocDir(dest, "", path); err != nil {
					return fmt.Errorf("error evaluating symlink: %w", err)
				} else if escapes {
					return fmt.Errorf("archive contains symlink that escapes alloc dir")
				}
			}

			continue
		}
		// If the header is a file, we write to a file
		if hdr.Typeflag == tar.TypeReg {
			fPath := filepath.Join(dest, hdr.Name)
			if _, err := os.Lstat(fPath); err == nil {
				if err := os.Remove(fPath); err != nil {
					return fmt.Errorf("error removing existing file: %w", err)

View on GitHub (pinned to 482b49bf1a)

Solutions

  1. Remove any pre-existing file/dir at the destination path before extraction
  2. Ensure the parent directory for the symlink was created earlier in the archive
  3. On Windows, run the client with SeCreateSymbolicLinkPrivilege
  4. Verify the alloc dir filesystem permits symlink creation

Example fix

// before
if err = os.Symlink(hdr.Linkname, filepath.Join(dest, hdr.Name)); err != nil {
    return fmt.Errorf("error creating symlink: %w", err)
}
// after
linkPath := filepath.Join(dest, hdr.Name)
if _, err := os.Lstat(linkPath); err == nil {
    os.Remove(linkPath)
}
if err = os.Symlink(hdr.Linkname, linkPath); err != nil {
    return fmt.Errorf("error creating symlink: %w", err)
}
Defensive patterns

Strategy: validation

Validate before calling

// Pre-check the destination path is clear and FS supports symlinks:
// link := filepath.Join(dest, "__probe__"); os.Symlink(".", link); os.Remove(link)

Try / catch

if err := watcher.Wait(ctx); err != nil {
    if strings.Contains(err.Error(), "error creating symlink") {
        // clean stale extraction dir and retry
        os.RemoveAll(dest)
        return retryMigration(ctx, alloc)
    }
    return err
}

Prevention

When it happens

Trigger: streamAllocDir processes a tar.TypeSymlink header and the symlink creation syscall returns an error (EEXIST, ENOENT on parent, EPERM on symlink-restricted filesystems).

Common situations: Stale file already at the destination path from an earlier extraction; Windows without symlink privilege; filesystems mounted with symlinks disabled; duplicate entries in the archive.

Related errors


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