{"record":{"id":"eb1ea8a8ef6cf4c2","repo":"kubernetes/kops","slug":"server-side-addons-client-does-not-support-addons","errorCode":null,"errorMessage":"server-side addons client does not support Addons::Replace","messagePattern":"server-side addons client does not support Addons::Replace","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cmd/kops-controller/pkg/controllerclientset/addons.go","lineNumber":53,"sourceCode":"}\n\nvar _ simple.AddonsClient = &addonsClient{}\n\nfunc newAddonsClient(basePath vfs.Path, cluster *kops.Cluster) *addonsClient {\n\tif cluster == nil || cluster.Name == \"\" {\n\t\tklog.Fatalf(\"cluster / cluster.Name is required\")\n\t}\n\n\tr := &addonsClient{\n\t\tbasePath: basePath,\n\t\tcluster:  cluster,\n\t}\n\n\treturn r\n}\n\nfunc (c *addonsClient) Replace(addons kubemanifest.ObjectList) error {\n\treturn fmt.Errorf(\"server-side addons client does not support Addons::Replace\")\n}\n\nfunc (c *addonsClient) List(ctx context.Context) (kubemanifest.ObjectList, error) {\n\tconfigPath := c.basePath.Join(\"default\")\n\n\tb, err := configPath.ReadFile(ctx)\n\tif err != nil {\n\t\tif os.IsNotExist(err) {\n\t\t\treturn nil, nil\n\t\t}\n\t\treturn nil, fmt.Errorf(\"error reading addons file %s: %v\", configPath, err)\n\t}\n\n\tobjects, err := kubemanifest.LoadObjectsFrom(b)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n","sourceCodeStart":35,"sourceCodeEnd":71,"githubUrl":"https://github.com/kubernetes/kops/blob/4c8573c808a73d578c5eadc86d410646ea0b0d73/cmd/kops-controller/pkg/controllerclientset/addons.go#L35-L71","documentation":"The controller-side addons clientset is a read-only, server-side view of addons rendered from local files. Replace (mutating an addons list) is intentionally unimplemented and always returns this sentinel error. It signals 'this operation is not supported by this client', not a transient failure.","triggerScenarios":"Any code path calls addonsClient.Replace(addons) — e.g. RunCreate or CreateClusterConfig invoking the addons clientset from within kops-controller, where only List/Get-style reads are supported.","commonSituations":"Reusing kops bootstrup/create code (which does addons replace) inside the controller; a new feature tried to apply addon changes via the controller clientset instead of `kops replace`/the admin CLI.","solutions":["Refactor the calling code to skip addon replacement when running controller-side, or use the full kops CLI clientset","Guard the call site: only invoke Replace from tooling that uses the file-backed admin clientset","If addon mutation is needed from the controller, implement Replace in addonsClient against the API server"],"exampleFix":"// before\nif err := addonsClient.Replace(addons); err != nil {\n\treturn err\n}\n// after\nif err := addonsClient.Replace(addons); err != nil {\n\tif err.Error() == \"server-side addons client does not support Addons::Replace\" {\n\t\treturn nil // unsupported controller-side; managed via kops CLI\n\t}\n\treturn err\n}","handlingStrategy":"type-guard","validationCode":"// detect the unsupported client before mutating\ntype replacer interface{ Replace(kubemanifest.ObjectList) error }\nif _, ok := addonsClient.(replacer); !ok {\n\t// this clientset cannot Replace; route via kops CLI instead\n}","typeGuard":"func supportsReplace(c interface{}) bool {\n\tr, ok := c.(interface{ Replace(kubemanifest.ObjectList) error })\n\t_ = r\n\treturn ok\n}","tryCatchPattern":"if err := addonsClient.Replace(addons); err != nil {\n\tif err.Error() == \"server-side addons client does not support Addons::Replace\" {\n\t\treturn nil // expected on controller-side clientset\n\t}\n\treturn err\n}","preventionTips":["Know that controllerclientset is read-only; use kops CLI for addon mutations","Gate addons-apply code paths on clientset capability","Document Replace as unsupported in shared code"],"tags":["addons","clientset","unsupported-operation"],"backgroundTag":"unsupported-operation","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"}