{"record":{"id":"c41bd4cddd26283a","repo":"docker/cli","slug":"cowardly-refusing-to-save-to-a-terminal-use-the-c41bd4","errorCode":null,"errorMessage":"cowardly refusing to save to a terminal. Use the -o flag or redirect","messagePattern":"cowardly refusing to save to a terminal\\. Use the -o flag or redirect","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cli/command/image/save.go","lineNumber":73,"sourceCode":"func runSave(ctx context.Context, dockerCLI command.Cli, opts saveOptions) error {\n\tvar options []client.ImageSaveOption\n\n\tplatformList := []ocispec.Platform{}\n\tfor _, p := range opts.platform {\n\t\tpp, err := platforms.Parse(p)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"invalid platform: %w\", err)\n\t\t}\n\t\tplatformList = append(platformList, pp)\n\t}\n\tif len(platformList) > 0 {\n\t\toptions = append(options, client.ImageSaveWithPlatforms(platformList...))\n\t}\n\n\tvar output io.Writer\n\tif opts.output == \"\" {\n\t\tif dockerCLI.Out().IsTerminal() {\n\t\t\treturn errors.New(\"cowardly refusing to save to a terminal. Use the -o flag or redirect\")\n\t\t}\n\t\toutput = dockerCLI.Out()\n\t} else {\n\t\twriter, err := atomicwriter.New(opts.output, 0o600)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to save image: %w\", err)\n\t\t}\n\t\tdefer writer.Close()\n\t\toutput = writer\n\t}\n\n\tresponseBody, err := dockerCLI.Client().ImageSave(ctx, opts.images, options...)\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer responseBody.Close()\n\n\t_, err = io.Copy(output, responseBody)","sourceCodeStart":55,"sourceCodeEnd":91,"githubUrl":"https://github.com/docker/cli/blob/4f84911bfe8811e9b028e4b1fee8e7510be79387/cli/command/image/save.go#L55-L91","documentation":"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.","triggerScenarios":"Running `docker save myimage` in an interactive shell with no -o flag and no stdout redirection.","commonSituations":"Forgetting -o; intending to pipe but running interactively; expecting a file to be written automatically.","solutions":["Use -o to write a file: `docker save -o out.tar myimage`","Redirect stdout: `docker save myimage > out.tar`","Pipe to a consumer so stdout is not a TTY: `docker save myimage | gzip > out.tar.gz`"],"exampleFix":"// before\ndocker save myimage\n// after\ndocker save -o out.tar myimage\n// or\ndocker save myimage > out.tar","handlingStrategy":"validation","validationCode":"if opts.output == \"\" && dockerCLI.Out().IsTerminal() {\n    return errors.New(\"refusing to save to terminal; pass -o <file> or redirect stdout\")\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always pass -o <file> when saving images","Redirect stdout to a file in scripts: `docker save img > out.tar`","Detect TTY in wrapper scripts (`[ -t 1 ]`) before streaming binary"],"tags":["images","cli","terminal","stdin-stdout"],"backgroundTag":null,"analyzedSha":"4f84911bfe8811e9b028e4b1fee8e7510be79387","analyzedAt":"2026-08-07T12:15:29.814Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}