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

  1. Use only STDIN, STDOUT, or STDERR (any case) with --attach.
  2. If you meant to expose a device, use --device instead.
  3. 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

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


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)