{"record":{"id":"fd6c27d25203ef20","repo":"kubernetes/kops","slug":"failed-to-get-updates-w","errorCode":null,"errorMessage":"failed to get updates: %w","messagePattern":"failed to get updates: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"channels/pkg/cmd/apply_channel.go","lineNumber":229,"sourceCode":"\t\t}\n\t\tif err := applyMenu(ctx, menu, f.VFSContext(), k8sClient, cmClient, dynamicClient, restMapper, options.Yes); err != nil {\n\t\t\tmerr = multierr.Append(merr, fmt.Errorf(\"applying %q: %w\", channelLocation, err))\n\t\t}\n\t}\n\treturn merr\n}\n\nfunc applyMenu(ctx context.Context, menu *channels.AddonMenu, vfsContext *vfs.VFSContext, k8sClient kubernetes.Interface, cmClient certmanager.Interface, dynamicClient dynamic.Interface, restMapper *restmapper.DeferredDiscoveryRESTMapper, apply bool) error {\n\t// channelVersions is the list of installed addons in the cluster.\n\t// It is keyed by <namespace>:<addon name>.\n\tchannelVersions, err := getChannelVersions(ctx, k8sClient)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"cannot fetch channel versions from namespaces: %w\", err)\n\t}\n\n\tupdates, needUpdates, err := getUpdates(ctx, menu, k8sClient, cmClient, channelVersions)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to get updates: %w\", err)\n\t}\n\n\tif len(updates) == 0 {\n\t\tfmt.Printf(\"No update required\\n\")\n\t\treturn nil\n\t}\n\n\t{\n\t\tt := &tables.Table{}\n\t\tt.AddColumn(\"NAME\", func(r *channels.AddonUpdate) string {\n\t\t\treturn r.Name\n\t\t})\n\t\tt.AddColumn(\"CURRENT\", func(r *channels.AddonUpdate) string {\n\t\t\tif r.ExistingVersion == nil {\n\t\t\t\treturn \"-\"\n\t\t\t}\n\t\t\treturn r.ExistingVersion.ManifestHash\n\t\t})","sourceCodeStart":211,"sourceCodeEnd":247,"githubUrl":"https://github.com/kubernetes/kops/blob/4c8573c808a73d578c5eadc86d410646ea0b0d73/channels/pkg/cmd/apply_channel.go#L211-L247","documentation":"getUpdates compares each menu addon against installed channel versions via addon.GetRequiredUpdates. A per-addon error aborts the whole comparison and applyMenu wraps it as 'failed to get updates: %w', aborting before any changes are made.","triggerScenarios":"During applyMenu, one addon's GetRequiredUpdates errors — usually fetching the installed addon object or parsing its version annotation.","commonSituations":"Corrupt or unparsable version annotation left by an older kOps version, missing/modified addon resource in-cluster, cert-manager client or API read errors.","solutions":["Identify the offending addon from the wrapped cause","Fix or delete the in-cluster addon object with the malformed version/annotation","Ensure the channel's addon.yaml declares valid semver versions","Re-run apply after correcting in-cluster state"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"for name, cv := range channelVersions {\n\tif cv != nil && cv.Version != \"\" {\n\t\tif _, err := semver.Parse(cv.Version); err != nil {\n\t\t\treturn fmt.Errorf(\"addon %q has unparsable version %q; fix in-cluster state\", name, cv.Version)\n\t\t}\n\t}\n}","typeGuard":"func hasValidVersion(cv *channels.ChannelVersion) bool {\n\tif cv == nil || cv.Version == \"\" {\n\t\treturn true\n\t}\n\t_, err := semver.Parse(cv.Version)\n\treturn err == nil\n}","tryCatchPattern":"updates, needUpdates, err := getUpdates(ctx, menu, k8sClient, cmClient, channelVersions)\nif err != nil {\n\treturn fmt.Errorf(\"aborting apply before changes; fix addon state: %w\", err)\n}","preventionTips":["Never hand-edit addon version annotations in the cluster","Keep addon.yaml versions valid semver","Apply addon updates only through kops, not directly via kubectl"],"tags":["addons","versioning","kubernetes-api"],"backgroundTag":"addon-version-check-failed","analyzedSha":"4c8573c808a73d578c5eadc86d410646ea0b0d73","analyzedAt":"2026-09-05T04:13:19.212Z","contentChangedAt":"2026-09-05T04:13:19.212Z","schemaVersion":2},"datasetVersion":"2026-09-12T12:17:11.808Z"}