hashicorp/nomad · error

error chowning directory %w

Error message

error chowning directory %w

What it means

While extracting a directory entry from the alloc dir tar archive, Nomad creates the directory then attempts os.Chown with the Uid/Gid from the tar header. This error is returned when the chown fails — only attempted when running as euid 0 (root) on non-Windows.

Source

Thrown at client/allocwatcher/alloc_watcher.go:622

			// the message out of the file and return it.
			errBuf := make([]byte, int(hdr.Size))
			if _, err := tr.Read(errBuf); err != nil && err != io.EOF {
				return fmt.Errorf("error streaming previous alloc %q for new alloc %q; failed reading error message: %w",
					p.prevAllocID, p.allocID, err)
			}
			return fmt.Errorf("error streaming previous alloc %q for new alloc %q: %s",
				p.prevAllocID, p.allocID, string(errBuf))
		}

		// 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")
				}
			}

View on GitHub (pinned to 482b49bf1a)

Solutions

  1. Ensure the filesystem backing the data dir supports chown (avoid root-squashed NFS)
  2. Grant the Nomad client CAP_CHOWN if running in a container as root
  3. Verify the tar header Uid/Gid values are valid on the destination host
  4. Run the client as a non-root user to skip chown, if ownership does not matter
Defensive patterns

Strategy: validation

Validate before calling

// Confirm the destination filesystem supports chown and the client has the capability:
// touch a test file and os.Chown it with the expected uid/gid before starting the client

Try / catch

if err := watcher.Wait(ctx); err != nil {
    var pathErr *os.PathError
    if errors.As(err, &pathErr) && errors.Is(pathErr.Err, syscall.EPERM) {
        // fall back: run client without chown or fix capabilities
    }
    return err
}

Prevention

When it happens

Trigger: Running as root, streamAllocDir processes a tar.TypeDir header, MkdirAll succeeds, but os.Chown on the new directory fails (e.g. Uid/Gid not valid on the host, filesystem does not support chown).

Common situations: Migration across nodes with mismatched UID/GID ranges; containerized root lacking CAP_CHOWN; network filesystems (NFS with root squashing) rejecting chown.

Related errors


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