docker/cli · error

unable to setup input stream

Error message

unable to setup input stream: %s

What it means

Returned by hijackedIOStreamer.stream (hijack.go:64) when h.setupInput() fails. setupInput performs detach-keys validation and raw-terminal setup, so this error wraps whichever of those failed. It surfaces during `docker attach`/`exec`/interactive `run` over a hijacked connection.

Solutions

  1. Fix the --detach-keys value (see error 286).
  2. Ensure stdin is a real TTY: run from an interactive shell, not piped input, or drop -it.
  3. Verify the terminal emulator supports raw mode.
Defensive patterns

Strategy: validation

Validate before calling

// Pre-check both inputs to setupInput: detach keys and TTY availability:
if detachKeys != "" { if _, err := term.ToBytes(detachKeys); err != nil { return err } }
if isTTY && !term.IsTerminal(os.Stdin.Fd()) { return errors.New("stdin is not a TTY") }

Try / catch

// setupInput failures are user/environment errors; surface a hint rather than retry.
if err := streamer.stream(ctx); err != nil && strings.Contains(err.Error(), "unable to setup input stream") {
    fmt.Fprintln(os.Stderr, "check --detach-keys and TTY availability")
}

Prevention

When it happens

Trigger: An interactive container session where setupInput fails: invalid --detach-keys (most common), or a failure putting the input stream into raw mode for TTY handling.

Common situations: Bad --detach-keys value, a non-TTY stdin when a TTY was requested, or a terminal that cannot be set to raw mode.

Related errors


AI-assisted analysis of docker/cli@4f84911bfe (2026-08-07). Data as JSON: /api/errors/887f2283a64576f4. Report an issue: GitHub.

Appendix: source

Thrown at cli/command/container/hijack.go:64

	streams      command.Streams
	inputStream  io.ReadCloser
	outputStream io.Writer
	errorStream  io.Writer

	resp client.HijackedResponse

	tty        bool
	detachKeys string
}

// stream handles setting up the IO and then begins streaming stdin/stdout
// to/from the hijacked connection, blocking until it is either done reading
// output, the user inputs the detach key sequence when in TTY mode, or when
// the given context is cancelled.
func (h *hijackedIOStreamer) stream(ctx context.Context) error {
	restoreInput, err := h.setupInput()
	if err != nil {
		return fmt.Errorf("unable to setup input stream: %s", err)
	}

	defer restoreInput()

	outputDone := h.beginOutputStream(restoreInput)
	inputDone, detached := h.beginInputStream(restoreInput)

	select {
	case err := <-outputDone:
		return err
	case <-inputDone:
		// Input stream has closed.
		if h.outputStream != nil || h.errorStream != nil {
			// Wait for output to complete streaming.
			select {
			case err := <-outputDone:
				return err
			case <-ctx.Done():

View on GitHub (pinned to 4f84911bfe)