{"id":"96af2bc6895c01f1","repo":"docker/cli","slug":"plugin-upgrade-has-been-cancelled","errorCode":null,"errorMessage":"plugin upgrade has been cancelled","messagePattern":"plugin upgrade has been cancelled","errorType":"exception","errorClass":"cancelledErr","httpStatus":null,"severity":"info","filePath":"cli/command/plugin/upgrade.go","lineNumber":77,"sourceCode":"\tif err != nil {\n\t\treturn fmt.Errorf(\"error parsing remote upgrade image reference: %w\", err)\n\t}\n\tremote = reference.TagNameOnly(remote)\n\n\told, err := reference.ParseNormalizedNamed(res.Plugin.PluginReference)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error parsing current image reference: %w\", err)\n\t}\n\told = reference.TagNameOnly(old)\n\n\t_, _ = fmt.Fprintf(dockerCLI.Out(), \"Upgrading plugin %s from %s to %s\\n\", res.Plugin.Name, reference.FamiliarString(old), reference.FamiliarString(remote))\n\tif !opts.skipRemoteCheck && remote.String() != old.String() {\n\t\tr, err := prompt.Confirm(ctx, dockerCLI.In(), dockerCLI.Out(), \"Plugin images do not match, are you sure?\")\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif !r {\n\t\t\treturn cancelledErr{errors.New(\"plugin upgrade has been cancelled\")}\n\t\t}\n\t}\n\n\toptions, err := buildPullConfig(dockerCLI, opts)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tresponseBody, err := dockerCLI.Client().PluginUpgrade(ctx, opts.localName, client.PluginUpgradeOptions(options))\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer func() {\n\t\t_ = responseBody.Close()\n\t}()\n\tif err := jsonstream.Display(ctx, responseBody, dockerCLI.Out()); err != nil {\n\t\treturn err\n\t}","sourceCodeStart":59,"sourceCodeEnd":95,"githubUrl":"https://github.com/docker/cli/blob/e9452d6e785f6e365712b9d71bd7517591773c86/cli/command/plugin/upgrade.go#L59-L95","documentation":"Returned by `docker plugin upgrade` when the new remote image reference does not match the plugin's current reference and the user answers no to the 'Plugin images do not match, are you sure?' prompt. Wrapped in cancelledErr so it is recognized as a deliberate abort; nothing is pulled or changed.","triggerScenarios":"`docker plugin upgrade <name> <different-remote>` without --skip-remote-check, where the normalized/tagged remote differs from the installed plugin's PluginReference, and the confirmation prompt is declined.","commonSituations":"Switching a plugin to a different repository, tag, or registry mirror; automation upgrading to a retagged image and failing on the interactive prompt in a non-TTY environment.","solutions":["Answer 'y' at the prompt if the different image is intentional","Pass --skip-remote-check to bypass the reference-match confirmation in scripts","Use a remote that matches the installed plugin's reference (check `docker plugin inspect --format '{{.PluginReference}}' <name>`) if the mismatch was accidental"],"exampleFix":"# before\ndocker plugin upgrade myplugin registry2.example.com/myplugin:v2\n# after (intentional cross-repo upgrade in automation)\ndocker plugin upgrade --skip-remote-check myplugin registry2.example.com/myplugin:v2","handlingStrategy":null,"validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":[],"tags":["docker","plugin","upgrade","user-cancelled"],"analyzedSha":"e9452d6e785f6e365712b9d71bd7517591773c86","analyzedAt":"2026-08-01T07:09:22.474Z","schemaVersion":2}