{"record":{"id":"aa864e7a51539483","repo":"docker/cli","slug":"image-prune-has-been-cancelled","errorCode":null,"errorMessage":"image prune has been cancelled","messagePattern":"image prune has been cancelled","errorType":"console","errorClass":null,"httpStatus":null,"severity":"info","filePath":"cli/command/image/prune.go","lineNumber":86,"sourceCode":"\tdanglingWarning = `WARNING! This will remove all dangling images.\nAre you sure you want to continue?`\n)\n\nfunc runPrune(ctx context.Context, dockerCli command.Cli, options pruneOptions) (spaceReclaimed uint64, output string, err error) {\n\tpruneFilters := command.PruneFilters(dockerCli, options.filter.Value())\n\tpruneFilters.Add(\"dangling\", strconv.FormatBool(!options.all))\n\n\twarning := danglingWarning\n\tif options.all {\n\t\twarning = allImageWarning\n\t}\n\tif !options.force {\n\t\tr, err := prompt.Confirm(ctx, dockerCli.In(), dockerCli.Out(), warning)\n\t\tif err != nil {\n\t\t\treturn 0, \"\", err\n\t\t}\n\t\tif !r {\n\t\t\treturn 0, \"\", cancelledErr{errors.New(\"image prune has been cancelled\")}\n\t\t}\n\t}\n\n\tres, err := dockerCli.Client().ImagePrune(ctx, client.ImagePruneOptions{\n\t\tFilters: pruneFilters,\n\t})\n\tif err != nil {\n\t\treturn 0, \"\", err\n\t}\n\n\tvar sb strings.Builder\n\tif len(res.Report.ImagesDeleted) > 0 {\n\t\tsb.WriteString(\"Deleted Images:\\n\")\n\t\tfor _, st := range res.Report.ImagesDeleted {\n\t\t\tif st.Untagged != \"\" {\n\t\t\t\tsb.WriteString(\"untagged: \")\n\t\t\t\tsb.WriteString(st.Untagged)\n\t\t\t\tsb.WriteByte('\\n')","sourceCodeStart":68,"sourceCodeEnd":104,"githubUrl":"https://github.com/docker/cli/blob/4f84911bfe8811e9b028e4b1fee8e7510be79387/cli/command/image/prune.go#L68-L104","documentation":"Without --force, runPrune() shows a confirmation prompt; if the user declines it returns this error wrapped in a cancelledErr type that implements Cancelled(). It represents intentional cancellation, not a failure of the prune API itself. The same type is returned by the dry-run pruneFn path during `docker system prune`.","triggerScenarios":"`docker image prune` (no -f) then answering \"n\" at the confirmation prompt; a dry-run prune path where Confirmed is false.","commonSituations":"Interactive use where the user aborts; automation that hits the prompt unexpectedly because it omitted --force.","solutions":["Use --force/-f in automation to skip the prompt entirely","Treat a cancelledErr (Cancelled()) as a benign no-op, not a hard failure","Pre-confirm intent before invoking prune interactively"],"exampleFix":"// before\ndocker image prune   # then type n\n// after\ndocker image prune -f","handlingStrategy":"type-guard","validationCode":null,"typeGuard":"// cancelledErr implements Cancelled() — detect via interface type assertion\ntype cancelled interface{ Cancelled() }\n\nfunc isCancelled(err error) bool {\n    var c cancelled\n    return errors.As(err, &c)\n}","tryCatchPattern":"spaceReclaimed, output, err := runPrune(ctx, cli, opts)\nif err != nil {\n    var c interface{ Cancelled() }\n    if errors.As(err, &c) {\n        // benign: user declined the prompt; do not treat as a hard failure\n        return nil\n    }\n    return err\n}","preventionTips":["Pass --force/-f in automation to avoid the prompt entirely","Treat cancelledErr (Cancelled()) as a no-op, not a failure, in exit-code logic","Pre-validate intent before invoking prune in interactive flows"],"tags":["images","cli","user-cancellation"],"backgroundTag":null,"analyzedSha":"4f84911bfe8811e9b028e4b1fee8e7510be79387","analyzedAt":"2026-08-07T12:15:29.814Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}