{"record":{"id":"862e94b47d3f5bbb","repo":"kubernetes/kops","slug":"applying-patch-to-node-w","errorCode":null,"errorMessage":"applying patch to node: %w","messagePattern":"applying patch to node: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cmd/kops-controller/controllers/awsipam.go","lineNumber":187,"sourceCode":"\tnodePatchSpec := &nodePatchSpec{\n\t\tPodCIDRs: podCIDRs,\n\t}\n\tif len(podCIDRs) > 0 {\n\t\tnodePatchSpec.PodCIDR = podCIDRs[0]\n\t}\n\tnodePatch := &nodePatch{\n\t\tSpec: nodePatchSpec,\n\t}\n\tnodePatchJson, err := json.Marshal(nodePatch)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"building node patch: %w\", err)\n\t}\n\n\tklog.V(2).Infof(\"sending patch for node %q: %q\", node.Name, string(nodePatchJson))\n\n\t_, err = client.Nodes().Patch(ctx, node.Name, types.StrategicMergePatchType, nodePatchJson, metav1.PatchOptions{})\n\tif err != nil {\n\t\treturn fmt.Errorf(\"applying patch to node: %w\", err)\n\t}\n\n\treturn nil\n}\n","sourceCodeStart":169,"sourceCodeEnd":192,"githubUrl":"https://github.com/kubernetes/kops/blob/4c8573c808a73d578c5eadc86d410646ea0b0d73/cmd/kops-controller/controllers/awsipam.go#L169-L192","documentation":"patchNodePodCIDRs issues a strategic-merge PATCH against the Node resource (client.Nodes().Patch) to set spec.podCIDR/podCIDRs. This error wraps any failure returned by the Kubernetes API server for that patch request, such as RBAC denial, conflicts, validation rejection, or connectivity problems. Reconcile requeues and retries with backoff when this occurs.","triggerScenarios":"client.Nodes().Patch(ctx, node.Name, types.StrategicMergePatchType, nodePatchJson, metav1.PatchOptions{}) fails: the kops-controller service account lacks patch permission on nodes (RBAC), the API server rejects modifying an immutable/defaulted field (e.g. podCIDR already set or kube-controller-manager ownership conflict), a 409 conflict from a simultaneous update, or network/TLS errors reaching the API server.","commonSituations":"Cluster upgrades or kubebuilder RBAC markers (awsipam.go:92) not reflected in the deployed ClusterRole; kube-controller-manager node IPAM controller fighting over podCIDR assignment; the node object changed/removed concurrently; controller cannot reach the API server due to networking or an expired service-account token.","solutions":["Check the wrapped error and controller logs for the HTTP status: 403 means grant the service account patch/get/list/watch on nodes (the +kubebuilder:rbac marker at awsipam.go:92 must be rendered into the RBAC manifests).","For conflicts/validation errors on podCIDR, confirm the node's podCIDRs are actually empty (the controller only patches empty ones) and that kube-controller-manager's node IPAM controller is not assigning them concurrently.","Retry — controller-runtime requeues automatically; transient API server issues (timeouts, 5xx, token refresh) usually resolve on the next attempt.","Verify API server connectivity from the controller pod (dns, kubeconfig, CA/token mounts) if errors are connection-related."],"exampleFix":"// before\n_, err = client.Nodes().Patch(ctx, node.Name, types.StrategicMergePatchType, nodePatchJson, metav1.PatchOptions{})\nif err != nil {\n\treturn fmt.Errorf(\"applying patch to node: %w\", err)\n}\n// after\n_, err = client.Nodes().Patch(ctx, node.Name, types.StrategicMergePatchType, nodePatchJson, metav1.PatchOptions{})\nif err != nil {\n\tif apierrors.IsConflict(err) || apierrors.IsNotFound(err) {\n\t\tklog.V(2).Infof(\"skipping podCIDR patch for node %q: %v\", node.Name, err)\n\t\treturn nil\n\t}\n\treturn fmt.Errorf(\"applying patch to node: %w\", err)\n}","handlingStrategy":"retry","validationCode":"// pre-flight: verify RBAC allows patching nodes\nauthClient := authorizationv1.NewForConfigOrDie(restConfig)\nok, err := authClient.SelfSubjectAccessReviews().Create(ctx, &authorizationv1.SelfSubjectAccessReview{\n\tSpec: authorizationv1.SelfSubjectAccessReviewSpec{\n\t\tResourceAttributes: &authorizationv1.ResourceAttributes{Verb: \"patch\", Resource: \"nodes\"},\n\t},\n})\nif err != nil || !ok.Status.Allowed {\n\treturn fmt.Errorf(\"service account cannot patch nodes\")\n}","typeGuard":"func isRetryablePatchError(err error) bool {\n\treturn apierrors.IsConflict(err) || apierrors.IsServerTimeout(err) || apierrors.IsTooManyRequests(err)\n}","tryCatchPattern":"_, err = client.Nodes().Patch(ctx, node.Name, types.StrategicMergePatchType, nodePatchJson, metav1.PatchOptions{})\nif err != nil {\n\tswitch {\n\tcase apierrors.IsNotFound(err):\n\t\treturn nil // node deleted; nothing to patch\n\tcase apierrors.IsConflict(err) || apierrors.IsServerTimeout(err):\n\t\treturn fmt.Errorf(\"applying patch to node: %w\", err) // requeue/retry\n\tdefault:\n\t\treturn fmt.Errorf(\"applying patch to node: %w\", err)\n\t}\n}","preventionTips":["Ensure the deployed RBAC grants kops-controller patch (plus get/list/watch) on nodes, matching the +kubebuilder:rbac marker.","Confirm node.Spec.PodCIDRs is empty before patching; the controller must not fight kube-controller-manager IPAM.","Use the controller-runtime requeue/backoff instead of immediate manual retries on conflicts.","Check API server reachability and service-account token freshness when errors cluster around connectivity messages."],"tags":["kubernetes","rbac","patch","node"],"backgroundTag":"kubernetes-api-patch-failed","analyzedSha":"4c8573c808a73d578c5eadc86d410646ea0b0d73","analyzedAt":"2026-09-05T04:13:19.212Z","contentChangedAt":"2026-09-05T04:13:19.212Z","schemaVersion":2},"datasetVersion":"2026-09-12T07:17:12.445Z"}