nektos/act · error

valid streams are STDIN, STDOUT and STDERR

Error message

valid streams are STDIN, STDOUT and STDERR

What it means

validateAttach checks each --attach value (lowercased) against the set {stdin, stdout, stderr}; anything else returns 'valid streams are STDIN, STDOUT and STDERR'. Attach options tell Docker which standard streams to hook up for the container, and those three are the only streams that exist, so the parser rejects unknown values early instead of sending an invalid request to the daemon.

Source

Thrown at pkg/container/docker_cli.go:1146

		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 4f41128141)

Solutions

  1. Use only stdin, stdout, or stderr (any case): '--attach stderr'.
  2. Remove the --attach flag entirely if you did not intend it — act already wires up stdout/stderr for logging.
  3. Check the options string for typos introduced by YAML folding or quote stripping.

Example fix

# before
container:
  image: node:20
  options: --attach logs

# after
container:
  image: node:20
  options: --attach stderr
Defensive patterns

Strategy: validation

Validate before calling

package main

import (
	"fmt"
	"strings"
)

func validateAttachOptions(options string) error {
	fields := strings.Fields(options)
	for i, f := range fields {
		if f != "--attach" {
			continue
		}
		if i+1 >= len(fields) {
			return fmt.Errorf("--attach requires a value")
		}
		switch strings.ToLower(fields[i+1]) {
		case "stdin", "stdout", "stderr":
		default:
			return fmt.Errorf("--attach %s invalid: only stdin/stdout/stderr allowed", fields[i+1])
		}
	}
	return nil
}

Try / catch

if err := runJob(ctx); err != nil {
    if strings.Contains(err.Error(), "valid streams are STDIN, STDOUT and STDERR") {
        return errors.New("remove or correct the --attach value in container options (stdin|stdout|stderr only)")
    }
    return err
}

Prevention

When it happens

Trigger: A container options string like 'options: --attach logs' or '--attach STDIN,logs' where any element is not stdin/stdout/stderr (case-insensitive). Also values mangled by YAML quoting or shell-like splitting, e.g. '--attach stdin ' with a trailing token.

Common situations: Confusing --attach with --log-driver or --publish; passing a file/device name instead of a stream name; copy-paste from docker-compose 'attach' keys that expect a list and getting the syntax wrong in a single-line options string.

Related errors


AI-assisted analysis of nektos/act@4f41128141 (2026-08-15). Data as JSON: /api/errors/6610225e4ea20784. Report an issue: GitHub.