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
- Ensure the producer of the pipe writes the full payload and exits 0.
- Write the secret to a temp file and pass the path instead of `-`.
- 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
- Check the exit status of piped producers before relying on stdin.
- Prefer a file path over `-` in automated pipelines for reliability.
- Use LimitReader-equivalent bounds when forwarding stdin.
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
- error reading from
- error reading from STDIN: data is empty
- error reading from STDIN
- error reading from : data is empty
- error reading from STDIN: data is empty
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)