kubernetes/kops · error

building node patch: %w

Error message

building node patch: %w

What it means

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).

Source

Thrown at cmd/kops-controller/controllers/awsipam.go:180

	PodCIDR  string   `json:"podCIDR,omitempty"`
	PodCIDRs []string `json:"podCIDRs,omitempty"`
}

// patchNodePodCIDRs patches the node podCIDRs to the specified value(s).
func patchNodePodCIDRs(client *corev1client.CoreV1Client, ctx context.Context, node *corev1.Node, podCIDRs []string) error {
	klog.Infof("assigning podCIDRs %v to node %q", podCIDRs, node.ObjectMeta.Name)
	nodePatchSpec := &nodePatchSpec{
		PodCIDRs: podCIDRs,
	}
	if len(podCIDRs) > 0 {
		nodePatchSpec.PodCIDR = podCIDRs[0]
	}
	nodePatch := &nodePatch{
		Spec: nodePatchSpec,
	}
	nodePatchJson, err := json.Marshal(nodePatch)
	if err != nil {
		return fmt.Errorf("building node patch: %w", err)
	}

	klog.V(2).Infof("sending patch for node %q: %q", node.Name, string(nodePatchJson))

	_, err = client.Nodes().Patch(ctx, node.Name, types.StrategicMergePatchType, nodePatchJson, metav1.PatchOptions{})
	if err != nil {
		return fmt.Errorf("applying patch to node: %w", err)
	}

	return nil
}

View on GitHub (pinned to 4c8573c808)

Solutions

  1. Inspect the wrapped error (%w) to identify which field/type failed to marshal.
  2. Remove or fix the unmarshalable field or custom MarshalJSON implementation in the nodePatch/nodePatchSpec structs (awsipam.go:161-177).
  3. If a new field cannot be JSON-marshaled, convert it to a serializable representation (e.g. string) before building the patch.
  4. Verify the fix by adding a unit test that marshals a fully populated nodePatch.

Example fix

// before
type nodePatchSpec struct {
	PodCIDR  string   `json:"podCIDR,omitempty"`
	PodCIDRs []string `json:"podCIDRs,omitempty"`
	Extra    func()   // not JSON-serializable
}
// after
type nodePatchSpec struct {
	PodCIDR  string   `json:"podCIDR,omitempty"`
	PodCIDRs []string `json:"podCIDRs,omitempty"`
}
Defensive patterns

Strategy: try-catch

Validate before calling

// validate the patch serializes before building the reconciler path
if _, err := json.Marshal(&nodePatch{Spec: &nodePatchSpec{PodCIDR: cidr, PodCIDRs: []string{cidr}}}); err != nil {
	return fmt.Errorf("node patch not serializable: %w", err)
}

Type guard

func serializable(v any) bool {
	b, err := json.Marshal(v)
	return err == nil && b != nil
}

Try / catch

nodePatchJson, err := json.Marshal(nodePatch)
if err != nil {
	klog.Errorf("failed to marshal node patch for %s: %v", node.Name, err)
	return fmt.Errorf("building node patch: %w", err)
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Understand the failure class

Background: json.Marshal / "failed to marshal" errors in Go: why "unsupported type" happens and how to fix it — this error's family across 22 libraries.

Related errors


AI-assisted analysis of kubernetes/kops@4c8573c808 (2026-09-05). Data as JSON: /api/errors/eae8bf106583d495. Report an issue: GitHub.