containerd/containerd · error
failed to open stdin fifo: %w
Error message
failed to open stdin fifo: %w
What it means
openFifos opens the container's stdio FIFOs so IO can be copied between the shim and the client. This error wraps fifo.OpenFifo failing for the stdin fifo, which is opened write-only, non-blocking, with create. When it fails, no IO setup is usable and the error propagates out of NewDirectIO/copyIO, aborting task IO setup.
Source
Thrown at pkg/cio/io_unix.go:118
for _, c := range pipes.closers() {
if c != nil {
c.Close()
}
}
},
}, nil
}
func openFifos(ctx context.Context, fifos *FIFOSet) (f pipes, retErr error) {
defer func() {
if retErr != nil {
fifos.Close()
}
}()
if fifos.Stdin != "" {
if f.Stdin, retErr = fifo.OpenFifo(ctx, fifos.Stdin, syscall.O_WRONLY|syscall.O_CREAT|syscall.O_NONBLOCK, 0700); retErr != nil {
return f, fmt.Errorf("failed to open stdin fifo: %w", retErr)
}
defer func() {
if retErr != nil && f.Stdin != nil {
f.Stdin.Close()
}
}()
}
if fifos.Stdout != "" {
if f.Stdout, retErr = fifo.OpenFifo(ctx, fifos.Stdout, syscall.O_RDONLY|syscall.O_CREAT|syscall.O_NONBLOCK, 0700); retErr != nil {
return f, fmt.Errorf("failed to open stdout fifo: %w", retErr)
}
defer func() {
if retErr != nil && f.Stdout != nil {
f.Stdout.Close()
}
}()
}
if !fifos.Terminal && fifos.Stderr != "" {View on GitHub (pinned to 4246446a2b)
Solutions
- Verify the fifo directory (bundle root) exists, is writable, and is on a filesystem supporting named pipes.
- Remove stale leftover fifo files at the configured paths and retry the task creation.
- Check ulimit -n / fd leaks if this appears under load.
- Inspect the unwrapped errno (ENOENT, EACCES, ENOSPC, EMFILE) and address the specific resource condition.
Example fix
// before // /run/containerd/io.containerd.../fifos dir was removed by a cleanup script // after os.MkdirAll(fifoDir, 0o711) // ensure fifo dir exists before NewDirectIO f, err := cio.NewFIFOSetInDir(fifoDir, id, false)
Defensive patterns
Strategy: try-catch
Validate before calling
// Go: verify fifo paths are usable before opening IO
for _, p := range []string{fifos.Stdin, fifos.Stdout, fifos.Stderr} {
if p == "" { continue }
if info, err := os.Stat(p); err == nil && info.Mode()&os.ModeNamedPipe == 0 {
return fmt.Errorf("%s exists but is not a fifo", p)
}
}
if err := unix.Access(filepath.Dir(fifos.Stdin), unix.W_OK); err != nil {
return fmt.Errorf("fifo dir not writable: %w", err)
} Try / catch
f, err := cio.NewDirectIO(ctx, fifos)
if err != nil {
if errors.Is(err, syscall.EMFILE) { return errors.New("fd limit reached; raise ulimit -n") }
if errors.Is(err, syscall.ENOENT) { return errors.New("fifo dir missing; recreate bundle") }
return fmt.Errorf("io setup failed: %w", err)
}
defer f.Close() Prevention
- Keep the containerd IO fifo directory intact; exclude it from cleanup scripts
- Raise RLIMIT_NOFILE in high container-density environments
- Clean up stale fifos from crashed runs before recreating tasks with the same ID
When it happens
Trigger: Creating a direct-IO task (NewDirectIO / WithFIFOs) where opening fifos.Stdin with syscall.O_WRONLY|O_CREAT|O_NONBLOCK fails — path doesn't exist and can't be created, the parent directory is missing or not writable, too many open fds, or a fifo path pointing at an existing non-fifo file (ENXIO/EEXIST mismatch).
Common situations: FIFO directory deleted between container create and start; bundle path on a read-only or full filesystem; fd exhaustion under high container density; leftover stale fifo files from a previous crashed run.
Related errors
- cannot attach, missing fifos
- timeout creating new loopback device
- mount options is too long
- unprivileged_icmp and unprivileged_port require kernel versi
- failed to open %s: %w
AI-assisted analysis of containerd/containerd@4246446a2b (2026-09-02).
Data as JSON: /api/errors/e4aba013fa39cf5c.
Report an issue: GitHub.