hashicorp/nomad · error

failed to create parent directories of %q: %w

Error message

failed to create parent directories of %q: %w

What it means

Thrown by `writeBytes` in the operator debug collector when `escapingfs.EnsurePath` fails to create the parent directory tree for an output file inside the capture directory. Nomad wraps the filesystem error (permission denied, not a directory, read-only fs, etc.) along with the target directory path.

Source

Thrown at command/operator_debug.go:1405

	c.writeBody(dir, "vault-sys-health.json", resp, err)

	return nil
}

// writeBytes writes a file to the archive, recording it in the manifest
func (c *OperatorDebugCommand) writeBytes(dir, file string, data []byte) error {
	// Replace invalid characters in filename
	filename := helper.CleanFilename(file, "_")

	relativePath := filepath.Join(dir, filename)
	c.manifest = append(c.manifest, relativePath)
	dirPath := filepath.Join(c.collectDir, dir)
	filePath := filepath.Join(dirPath, filename)

	// Ensure parent directories exist
	err := escapingfs.EnsurePath(dirPath, true)
	if err != nil {
		return fmt.Errorf("failed to create parent directories of %q: %w", dirPath, err)
	}

	// Ensure filename doesn't escape the sandbox of the capture directory
	escapes := escapingfs.PathEscapesSandbox(c.collectDir, filePath)
	if escapes {
		return fmt.Errorf("file path %q escapes capture directory %q", filePath, c.collectDir)
	}

	// Create the file
	fh, err := os.Create(filePath)
	if err != nil {
		return fmt.Errorf("failed to create file %q, err: %w", filePath, err)
	}
	defer fh.Close()

	_, err = fh.Write(data)
	if err != nil {
		return fmt.Errorf("Failed to write data to file %q, err: %w", filePath, err)

View on GitHub (pinned to 482b49bf1a)

Solutions

  1. Inspect the wrapped cause: permission denied means fix ownership/permissions (`chown`/`chmod`) on the output directory.
  2. Check that no regular file exists at a path component of the target directory; remove or rename it.
  3. Choose a writable output directory via the debug command's output flag, e.g. a path under the invoking user's home.
  4. Verify the filesystem is not full or mounted read-only (`df -h`, `mount | grep <path>`).

Example fix

// before (shell)
sudo nomad operator debug -output /root/debug
// after
nomad operator debug -output "$HOME/debug"
Defensive patterns

Strategy: validation

Validate before calling

out := flagOutput
if info, err := os.Stat(out); err == nil && !info.IsDir() {
    return fmt.Errorf("output path %q exists and is not a directory", out)
}
probe := filepath.Join(out, ".write-test")
if err := os.WriteFile(probe, nil, 0o600); err != nil {
    return fmt.Errorf("output dir %q not writable: %w", out, err)
}
os.Remove(probe)

Prevention

When it happens

Trigger: Calling writeBytes (via writeBody, writeError, collectPprof, savePprofProfile) when the directory `filepath.Join(c.collectDir, dir)` cannot be created: parent path component is a file, permission denied, disk full/read-only filesystem.

Common situations: Running `nomad operator debug` as a non-root user targeting a -output dir owned by root; SELinux/AppArmor restrictions; the output path contains a regular file where a directory is expected; full or read-only disk on the node.

Understand the failure class

Background: mkdir permission denied (EACCES): failed to create directory errors explained — this error's family across 32 libraries.

Related errors


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