{"record":{"id":"eae8bf106583d495","repo":"kubernetes/kops","slug":"building-node-patch-w-eae8bf","errorCode":null,"errorMessage":"building node patch: %w","messagePattern":"building node patch: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cmd/kops-controller/controllers/awsipam.go","lineNumber":180,"sourceCode":"\tPodCIDR  string   `json:\"podCIDR,omitempty\"`\n\tPodCIDRs []string `json:\"podCIDRs,omitempty\"`\n}\n\n// patchNodePodCIDRs patches the node podCIDRs to the specified value(s).\nfunc patchNodePodCIDRs(client *corev1client.CoreV1Client, ctx context.Context, node *corev1.Node, podCIDRs []string) error {\n\tklog.Infof(\"assigning podCIDRs %v to node %q\", podCIDRs, node.ObjectMeta.Name)\n\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":162,"sourceCodeEnd":192,"githubUrl":"https://github.com/kubernetes/kops/blob/4c8573c808a73d578c5eadc86d410646ea0b0d73/cmd/kops-controller/controllers/awsipam.go#L162-L192","documentation":"patchNodePodCIDRs marshals a nodePatch struct (spec.podCIDR/podCIDRs fields) to JSON via encoding/json before sending it to the Kubernetes API. This error is returned when json.Marshal fails. In practice this is nearly impossible for this fixed struct (all fields are plain strings/slices with omitempty tags), so it indicates a programming-level problem such as a change introducing unmarshalable types (e.g. a channel or func field, or a custom MarshalJSON that fails).","triggerScenarios":"json.Marshal(nodePatch) returns an error, which for this struct can only happen if nodePatchSpec's types are changed to include unsupported kinds (chan, func, complex), a field gets an invalid custom MarshalJSON method, or a circular type is introduced.","commonSituations":"A developer extends nodePatchSpec with a new field whose type (or pointer-chained type) is not JSON-serializable, or adds a custom marshaler returning an error; not something an end user triggers via configuration.","solutions":["Inspect the wrapped error (%w) to identify which field/type failed to marshal.","Remove or fix the unmarshalable field or custom MarshalJSON implementation in the nodePatch/nodePatchSpec structs (awsipam.go:161-177).","If a new field cannot be JSON-marshaled, convert it to a serializable representation (e.g. string) before building the patch.","Verify the fix by adding a unit test that marshals a fully populated nodePatch."],"exampleFix":"// before\ntype nodePatchSpec struct {\n\tPodCIDR  string   `json:\"podCIDR,omitempty\"`\n\tPodCIDRs []string `json:\"podCIDRs,omitempty\"`\n\tExtra    func()   // not JSON-serializable\n}\n// after\ntype nodePatchSpec struct {\n\tPodCIDR  string   `json:\"podCIDR,omitempty\"`\n\tPodCIDRs []string `json:\"podCIDRs,omitempty\"`\n}","handlingStrategy":"try-catch","validationCode":"// validate the patch serializes before building the reconciler path\nif _, err := json.Marshal(&nodePatch{Spec: &nodePatchSpec{PodCIDR: cidr, PodCIDRs: []string{cidr}}}); err != nil {\n\treturn fmt.Errorf(\"node patch not serializable: %w\", err)\n}","typeGuard":"func serializable(v any) bool {\n\tb, err := json.Marshal(v)\n\treturn err == nil && b != nil\n}","tryCatchPattern":"nodePatchJson, err := json.Marshal(nodePatch)\nif err != nil {\n\tklog.Errorf(\"failed to marshal node patch for %s: %v\", node.Name, err)\n\treturn fmt.Errorf(\"building node patch: %w\", err)\n}","preventionTips":["Keep nodePatch/nodePatchSpec fields restricted to JSON-serializable types (string, []string, pointers to those).","Add a unit test marshaling a fully populated nodePatch to catch regressions early.","Avoid custom MarshalJSON methods on patch structs unless covered by tests.","Since this error is developer-induced, run go test ./cmd/kops-controller/... before merging struct changes."],"tags":["kubernetes","json","serialization"],"backgroundTag":"json-marshal-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"}