docker/cli · error

error reading from STDIN

Error message

error reading from STDIN: %w

What it means

Returned by readSecretData (secret/create.go:131) wrapping the error from io.ReadAll when reading the secret payload from STDIN (the `-` filename). Input is limited to 2*maxSecretSize (~1MB) via LimitReader; an I/O failure during that read produces this wrapped error.

Solutions

  1. Ensure the producer of the pipe writes the full payload and exits 0.
  2. Write the secret to a temp file and pass the path instead of `-`.
  3. Check the upstream command for errors when chaining into docker secret create.

Example fix

// before
produce-secret | docker secret create mysecret -   # producer fails
// after
produce-secret > /tmp/secret.txt && docker secret create mysecret /tmp/secret.txt && rm /tmp/secret.txt
Defensive patterns

Strategy: try-catch

Try / catch

// On stdin read failure, fall back to a file source.
data, err := readSecretData(in, "-")
if err != nil {
    if strings.Contains(err.Error(), "error reading from STDIN") {
        // producer pipe broke; retry from a temp file
        return readSecretData(os.Open(tempFile))
    }
    return err
}

Prevention

When it happens

Trigger: Running `echo $SECRET | docker secret create mysecret -` and the stdin pipe breaks or the reader returns an error mid-stream. Also possible if stdin is closed prematurely by the producing process.

Common situations: A piped producer exits non-zero before closing stdout, a broken pipe in CI, or redirecting from a special file that errors on read.

Related errors


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

Appendix: source

Thrown at cli/command/secret/create.go:131

}

// maxSecretSize is the maximum byte length of the [swarm.SecretSpec.Data] field,
// as defined by [MaxSecretSize] in SwarmKit.
//
// [MaxSecretSize]: https://pkg.go.dev/github.com/moby/swarmkit/v2@v2.0.0-20250103191802-8c1959736554/api/validation#MaxSecretSize
const maxSecretSize = 500 * 1024 // 500KB

// readSecretData reads the secret from either stdin or the given fileName.
//
// It reads up to twice the maximum size of the secret ([maxSecretSize]),
// just in case swarm's limit changes; this is only a safeguard to prevent
// reading arbitrary files into memory.
func readSecretData(in io.Reader, fileName string) ([]byte, error) {
	switch fileName {
	case "-":
		data, err := io.ReadAll(io.LimitReader(in, 2*maxSecretSize))
		if err != nil {
			return nil, fmt.Errorf("error reading from STDIN: %w", err)
		}
		if len(data) == 0 {
			return nil, errors.New("error reading from STDIN: data is empty")
		}
		return data, nil
	case "":
		return nil, errors.New("secret file is required")
	default:
		// Open file with [FILE_FLAG_SEQUENTIAL_SCAN] on Windows, which
		// prevents Windows from aggressively caching it. We expect this
		// file to be only read once. Given that this is expected to be
		// a small file, this may not be a significant optimization, so
		// we could choose to omit this, and use a regular [os.Open].
		//
		// [FILE_FLAG_SEQUENTIAL_SCAN]: https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilea#FILE_FLAG_SEQUENTIAL_SCAN
		f, err := sequential.Open(fileName)
		if err != nil {
			return nil, fmt.Errorf("error reading from %s: %w", fileName, err)

View on GitHub (pinned to 4f84911bfe)