hashicorp/nomad · error

failed to create file %q: %w

Error message

failed to create file %q: %w

What it means

Thrown inside the writerGetter closure of the operator debug package when `os.Create(filePath)` fails while opening an archive file for writing. It is the writer-producing counterpart of the writeBytes create error and wraps the underlying OS error with the file path.

Source

Thrown at command/operator_debug.go:1475

// newFile returns a func that creates a new file for writing and returns it as
// an io.WriterCloser interface. The caller is responsible for closing the
// io.Writer when its done.
//
// Note: methods cannot be generic in go, so this function returns a function
// that closes over our command so that we can still reference the command
// object's fields to validate the file. In future iterations it might be nice
// if we could move most of the command into standalone functions.
func (c *OperatorDebugCommand) newFile(dir, file string) writerGetter {
	return func() (io.WriteCloser, error) {
		filePath, err := c.newFilePath(dir, file)
		if err != nil {
			return nil, err
		}

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

// writeResponseToFile writes a response object to a file. It returns an error
// that the caller should report to the UI.
func writeResponseToFile(obj any, getWriterFn writerGetter) error {

	writer, err := getWriterFn()
	if err != nil {
		return err
	}
	defer writer.Close()

	err = writeJSON(obj, writer)
	if err != nil {
		return err

View on GitHub (pinned to 482b49bf1a)

Solutions

  1. Check the wrapped OS error and fix accordingly (permissions, ulimit, stale directory).
  2. Ensure the process user can write to the capture/output directory.
  3. Raise the open-file limit if many captures run concurrently (`ulimit -n 4096`).
  4. Verify disk space on the output volume.

Example fix

// before (shell)
ulimit -n   # 256, too low for concurrent captures
// after
ulimit -n 4096 && nomad operator debug -output "$HOME/debug"
Defensive patterns

Strategy: try-catch

Validate before calling

if err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &r); err == nil && r.Cur < 1024 {
    return fmt.Errorf("open-file limit %d too low for capture", r.Cur)
}

Try / catch

writer, err := writerGetter()
if err != nil {
    var pe *fs.PathError
    if errors.As(err, &pe) && (errors.Is(pe.Err, syscall.EACCES) || errors.Is(pe.Err, syscall.EMFILE)) {
        // fix permissions or fd limit, then retry once
    }
    return err
}

Prevention

When it happens

Trigger: os.Create failing for a validated path during capture setup: permission denied on collectDir, too many open file descriptors, target path is an existing directory, ENOSPC.

Common situations: Debug collection running under a user lacking write access; long captures exhausting file descriptors; leftover directory at the archive path.

Related errors


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