docker/cli · error

cowardly refusing to save to a terminal. Use the -o flag or…

Error message

cowardly refusing to save to a terminal. Use the -o flag or redirect

What it means

runSave() streams a binary tar archive of image layers to stdout by default. If no -o file is given and stdout is a TTY (dockerCLI.Out().IsTerminal()), it refuses to avoid dumping binary onto the terminal. The guard mirrors the export-to-terminal protection.

Solutions

  1. Use -o to write a file: `docker save -o out.tar myimage`
  2. Redirect stdout: `docker save myimage > out.tar`
  3. Pipe to a consumer so stdout is not a TTY: `docker save myimage | gzip > out.tar.gz`

Example fix

// before
docker save myimage
// after
docker save -o out.tar myimage
// or
docker save myimage > out.tar
Defensive patterns

Strategy: validation

Validate before calling

if opts.output == "" && dockerCLI.Out().IsTerminal() {
    return errors.New("refusing to save to terminal; pass -o <file> or redirect stdout")
}

Prevention

When it happens

Trigger: Running `docker save myimage` in an interactive shell with no -o flag and no stdout redirection.

Common situations: Forgetting -o; intending to pipe but running interactively; expecting a file to be written automatically.

Related errors


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

Appendix: source

Thrown at cli/command/image/save.go:73

func runSave(ctx context.Context, dockerCLI command.Cli, opts saveOptions) error {
	var options []client.ImageSaveOption

	platformList := []ocispec.Platform{}
	for _, p := range opts.platform {
		pp, err := platforms.Parse(p)
		if err != nil {
			return fmt.Errorf("invalid platform: %w", err)
		}
		platformList = append(platformList, pp)
	}
	if len(platformList) > 0 {
		options = append(options, client.ImageSaveWithPlatforms(platformList...))
	}

	var output io.Writer
	if opts.output == "" {
		if dockerCLI.Out().IsTerminal() {
			return errors.New("cowardly refusing to save to a terminal. Use the -o flag or redirect")
		}
		output = dockerCLI.Out()
	} else {
		writer, err := atomicwriter.New(opts.output, 0o600)
		if err != nil {
			return fmt.Errorf("failed to save image: %w", err)
		}
		defer writer.Close()
		output = writer
	}

	responseBody, err := dockerCLI.Client().ImageSave(ctx, opts.images, options...)
	if err != nil {
		return err
	}
	defer responseBody.Close()

	_, err = io.Copy(output, responseBody)

View on GitHub (pinned to 4f84911bfe)