hashicorp/nomad · error
error opening writer at %s: %w
Error message
error opening writer at %s: %w
What it means
OpenWriter opens the FIFO itself for writing after successfully opening the parent directory via os.Root. This error wraps a failure of root.OpenFile(base, os.O_WRONLY) — the file exists check fails (ENOENT), permissions deny write (EACCES), or the O_NOFOLLOW-protected open rejects a symlink. Opening a FIFO for write also fails with ENXIO if no reader is listening.
Source
Thrown at client/lib/fifo/fifo_unix.go:64
}
return f, nil
}
// OpenWriter opens a fifo file for writer, assuming it already exists, returns io.WriteCloser
func OpenWriter(path string) (io.WriteCloser, error) {
dir := filepath.Dir(path)
base := filepath.Base(path)
root, err := os.OpenRoot(dir)
if err != nil {
return nil, fmt.Errorf("error opening fifo parent directory %q: %w", dir, err)
}
defer root.Close()
// also uses O_NOFOLLOW under the hood
f, err := root.OpenFile(base, os.O_WRONLY, 0)
if err != nil {
return nil, fmt.Errorf("error opening writer at %s: %w", path, err)
}
return f, nil
}
// Remove a fifo that already exists at a given path
func Remove(path string) error {
dir := filepath.Dir(path)
base := filepath.Base(path)
root, err := os.OpenRoot(dir)
if err != nil {
return fmt.Errorf("error opening root dir %q: %w", dir, err)
}
defer root.Close()
return root.Remove(base)
}
View on GitHub (pinned to 482b49bf1a)
Solutions
- Ensure the FIFO exists first: call fifo.Create(path, mode) or start the reader before the writer
- On ENXIO, verify a reader (OpenReader/CreateAndRead) is open on the FIFO before writing
- Remove and recreate stale or symlinked FIFOs with fifo.Remove + fifo.Create
- Check write permissions on the FIFO for the writing user
Example fix
// before
w, err := fifo.OpenWriter("/run/containerd/io/stdout")
// after
if err := fifo.Create("/run/containerd/io/stdout", 0o600); err != nil && !errors.Is(err, os.ErrExist) { return err }
w, err := fifo.OpenWriter("/run/containerd/io/stdout") Defensive patterns
Strategy: retry
Validate before calling
fi, err := os.Lstat(path)
if err != nil || fi.Mode()&os.ModeNamedPipe == 0 {
return fmt.Errorf("fifo %s not present", path)
} Type guard
func isENXIO(err error) bool {
return errors.Is(err, syscall.ENXIO)
} Try / catch
w, err := fifo.OpenWriter(path)
if err != nil {
switch {
case errors.Is(err, fs.ErrNotExist):
// create fifo then retry open
case errors.Is(err, syscall.ENXIO):
// no reader attached; wait for reader and retry
}
return err
} Prevention
- Start the reader before opening the writer, or handle ENXIO with retry
- Never symlink the fifo path; O_NOFOLLOW will reject it
- Create the FIFO idempotently and tolerate os.ErrExist
- Verify write permissions on the fifo for the writer user
When it happens
Trigger: Calling fifo.OpenWriter(path) when the FIFO was not created (ENOENT), the process lacks write permission (EACCES), the target is a symlink (O_NOFOLLOW rejection), or no reader has the FIFO open (ENXIO).
Common situations: Writer started before the log-monitor created the FIFO; FIFO removed by cleanup between creation and open; path replaced by symlink after a previous insecure setup; ENXIO when the reader process died.
Related errors
- error opening reader at %s: %w
- error opening root dir %q: %w
- Windows directory creation not supported on this platform
- failed to create secrets/envoy_bootstrap.json for envoy: %w
- failed to create alloc/logs/envoy_bootstrap.stderr.0 for env
AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04).
Data as JSON: /api/errors/f6007bca391f25c3.
Report an issue: GitHub.