kubernetes/kops · error
marshaling cluster config: %w
Error message
marshaling cluster config: %w
What it means
Returned by HCloudClusterConfig when the JSON encoder fails to serialize the Hetzner Cloud ClusterConfig struct. json.Encoder.Encode only fails if the config contains a value that cannot be marshaled (e.g. an unsupported type like chan or func, or a custom MarshalJSON returning an error). The error is wrapped so the underlying marshal cause is preserved.
Source
Thrown at upup/pkg/fi/cloudup/template_functions.go:1250
CloudInit: string(userDataBytes),
Labels: nodeLabels,
ServerLabels: serverLabels,
Taints: taints,
// Map the node group's image to both arches, since the autoscaler resolves the arch.
ImagesForArch: map[string]string{
"amd64": ig.Spec.Image,
"arm64": ig.Spec.Image,
},
}
}
// Use an encoder with HTML escaping disabled so the embedded cloud-init script stays readable.
var buf bytes.Buffer
enc := json.NewEncoder(&buf)
enc.SetEscapeHTML(false)
enc.SetIndent("", " ")
if err := enc.Encode(config); err != nil {
return "", fmt.Errorf("marshaling cluster config: %w", err)
}
// Strip the trailing newline that json.Encoder.Encode appends.
return strings.TrimRight(buf.String(), "\n"), nil
}
// HCloudSSHKey returns HCLOUD_SSH_KEY as the first SSH key ID.
func (tf *TemplateFunctions) HCloudSSHKey() (string, error) {
tasks, err := tf.TasksByType("SSHKey")
if err != nil {
return "", fmt.Errorf("listing SSH key tasks: %w", err)
}
if len(tasks) == 0 {
return "", nil
}
// Use the first SSH key, since the autoscaler accepts a single HCLOUD_SSH_KEY.
sshKey, ok := tasks[0].(*hetznertasks.SSHKey)View on GitHub (pinned to 4c8573c808)
Solutions
- Read the wrapped cause (%w) to identify the field/type that failed to marshal
- Inspect the ClusterConfig built by HCloudClusterConfig for newly added or non-standard field types
- Ensure any custom MarshalJSON implementations on config types handle nil receivers and edge cases
- If a field cannot be JSON-encoded, change its type or add an explicit MarshalJSON
Example fix
// before: config contains an unsupported field type
resp, err := tf.HCloudClusterConfig()
// after: guard against marshal failure and surface the underlying cause
if err != nil {
return fmt.Errorf("hcloud cluster config: %w", err) // cause names the bad field
} Defensive patterns
Strategy: try-catch
Validate before calling
// ensure config only contains JSON-encodable types before calling
b, err := json.Marshal(config)
if err != nil { /* fix offending field before rendering */ } Type guard
func isJSONEncodable(v interface{}) bool { var b []byte; _, err := json.Marshal(v); return err == nil } Try / catch
cfg, err := tf.HCloudClusterConfig()
if err != nil {
return fmt.Errorf("hcloud cluster config unavailable: %w", err)
} Prevention
- Keep ClusterConfig fields JSON-serializable (no chan/func types)
- Test custom MarshalJSON implementations for nil receivers
- Run template rendering in CI to catch marshal regressions
- Inspect wrapped %w errors rather than only the top message
When it happens
Trigger: Calling HCloudClusterConfig (directly or via HCloudClusterConfigChecksum) when the assembled ClusterConfig contains a field of an unencodable type or a custom marshaler that errors.
Common situations: A new field added to the Hetzner cluster config struct has a type json cannot encode; a struct field implements json.Marshaler and returns an error; bad upstream data from cluster spec parsing produced an invalid nested value.
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
- unable to marshal JSON: %v
- error serializing secret: %v
- error building annotation patch: %v
- building node patch: %w
- error building node patch: %v
AI-assisted analysis of kubernetes/kops@4c8573c808 (2026-09-05).
Data as JSON: /api/errors/c477310aea5dcc25.
Report an issue: GitHub.