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
- Fix the --detach-keys value (see error 286).
- Ensure stdin is a real TTY: run from an interactive shell, not piped input, or drop -it.
- 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
- Ensure a real TTY for interactive sessions.
- Validate --detach-keys before attaching.
- Avoid piping stdin when -t is set.
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
- invalid detach keys ( )
- unable to set IO streams as raw terminal
- timeout waiting for stats
- cowardly refusing to export to a terminal, specify a file…
- cowardly refusing to save to a terminal. Use the -o flag or…
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)