docker/cli · error
valid streams are STDIN, STDOUT and STDERR
Error message
valid streams are STDIN, STDOUT and STDERR
What it means
Thrown by validateAttach when an --attach stream value is not one of stdin, stdout, stderr (case-insensitive). Docker can only attach to those three standard streams, so any other token is rejected. The check uses slices.Contains against the lowercased value.
Solutions
- Use only STDIN, STDOUT, or STDERR (any case) with --attach.
- If you meant to expose a device, use --device instead.
- If you meant to mount a file/dir, use -v/--mount.
Example fix
// before docker run --attach STDOT alpine // after docker run --attach STDOUT alpine
Defensive patterns
Strategy: validation
Validate before calling
var validStreams = []string{"stdin", "stdout", "stderr"}
func validAttach(val string) error {
if !slices.Contains(validStreams, strings.ToLower(val)) {
return errors.New("valid streams are STDIN, STDOUT and STDERR")
}
return nil
}
for _, a := range attachStreams {
if err := validAttach(a); err != nil {
return err
}
} Prevention
- Restrict the --attach token source to a constant set {STDIN,STDOUT,STDERR}.
- Do not feed free-form user input directly to --attach.
- Use --device for devices and --mount for files to avoid confusing them with streams.
When it happens
Trigger: `docker run --attach STDIN --attach SERIAL ...` where SERIAL is invalid. Any --attach value outside {stdin,stdout,stderr} after ToLower.
Common situations: Typing a stream name wrong (STDOT, STDIN2). Passing a device/file name to --attach by mistake (thinking it attaches a file). Confusing --attach with --device or --mount.
Related errors
- invalid storage option
- you must provide one or more flags when using this command
- cannot attach to a stopped container, start it first
- cannot attach to a paused container, unpause it first
- cannot attach to a restarting container, wait until it is…
AI-assisted analysis of docker/cli@4f84911bfe (2026-08-07).
Data as JSON: /api/errors/d14dcf7a64a9e6c6.
Report an issue: GitHub.
Appendix: source
Thrown at cli/command/container/opts.go:1139
if isValid := validator(split[2]); !isValid {
return val, fmt.Errorf("bad mode specified: %s", mode)
}
val = fmt.Sprintf("%s:%s:%s", split[0], containerPath, mode)
}
if !path.IsAbs(containerPath) {
return val, fmt.Errorf("%s is not an absolute path", containerPath)
}
return val, nil
}
// validateAttach validates that the specified string is a valid attach option.
func validateAttach(val string) (string, error) {
s := strings.ToLower(val)
if slices.Contains([]string{"stdin", "stdout", "stderr"}, s) {
return s, nil
}
return val, errors.New("valid streams are STDIN, STDOUT and STDERR")
}
func toNetipAddrSlice(ips []string) []netip.Addr {
if len(ips) == 0 {
return nil
}
netIPs := make([]netip.Addr, 0, len(ips))
for _, ip := range ips {
addr, err := netip.ParseAddr(ip)
if err != nil {
continue
}
netIPs = append(netIPs, addr)
}
return netIPs
}
View on GitHub (pinned to 4f84911bfe)