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

  1. Verify the fifo directory (bundle root) exists, is writable, and is on a filesystem supporting named pipes.
  2. Remove stale leftover fifo files at the configured paths and retry the task creation.
  3. Check ulimit -n / fd leaks if this appears under load.
  4. 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

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


AI-assisted analysis of containerd/containerd@4246446a2b (2026-09-02). Data as JSON: /api/errors/e4aba013fa39cf5c. Report an issue: GitHub.