{"record":{"id":"c477310aea5dcc25","repo":"kubernetes/kops","slug":"marshaling-cluster-config-w","errorCode":null,"errorMessage":"marshaling cluster config: %w","messagePattern":"marshaling cluster config: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"upup/pkg/fi/cloudup/template_functions.go","lineNumber":1250,"sourceCode":"\t\t\tCloudInit:    string(userDataBytes),\n\t\t\tLabels:       nodeLabels,\n\t\t\tServerLabels: serverLabels,\n\t\t\tTaints:       taints,\n\t\t\t// Map the node group's image to both arches, since the autoscaler resolves the arch.\n\t\t\tImagesForArch: map[string]string{\n\t\t\t\t\"amd64\": ig.Spec.Image,\n\t\t\t\t\"arm64\": ig.Spec.Image,\n\t\t\t},\n\t\t}\n\t}\n\n\t// Use an encoder with HTML escaping disabled so the embedded cloud-init script stays readable.\n\tvar buf bytes.Buffer\n\tenc := json.NewEncoder(&buf)\n\tenc.SetEscapeHTML(false)\n\tenc.SetIndent(\"\", \"  \")\n\tif err := enc.Encode(config); err != nil {\n\t\treturn \"\", fmt.Errorf(\"marshaling cluster config: %w\", err)\n\t}\n\n\t// Strip the trailing newline that json.Encoder.Encode appends.\n\treturn strings.TrimRight(buf.String(), \"\\n\"), nil\n}\n\n// HCloudSSHKey returns HCLOUD_SSH_KEY as the first SSH key ID.\nfunc (tf *TemplateFunctions) HCloudSSHKey() (string, error) {\n\ttasks, err := tf.TasksByType(\"SSHKey\")\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"listing SSH key tasks: %w\", err)\n\t}\n\tif len(tasks) == 0 {\n\t\treturn \"\", nil\n\t}\n\n\t// Use the first SSH key, since the autoscaler accepts a single HCLOUD_SSH_KEY.\n\tsshKey, ok := tasks[0].(*hetznertasks.SSHKey)","sourceCodeStart":1232,"sourceCodeEnd":1268,"githubUrl":"https://github.com/kubernetes/kops/blob/4c8573c808a73d578c5eadc86d410646ea0b0d73/upup/pkg/fi/cloudup/template_functions.go#L1232-L1268","documentation":"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.","triggerScenarios":"Calling HCloudClusterConfig (directly or via HCloudClusterConfigChecksum) when the assembled ClusterConfig contains a field of an unencodable type or a custom marshaler that errors.","commonSituations":"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.","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"],"exampleFix":"// before: config contains an unsupported field type\nresp, err := tf.HCloudClusterConfig()\n// after: guard against marshal failure and surface the underlying cause\nif err != nil {\n\treturn fmt.Errorf(\"hcloud cluster config: %w\", err) // cause names the bad field\n}","handlingStrategy":"try-catch","validationCode":"// ensure config only contains JSON-encodable types before calling\nb, err := json.Marshal(config)\nif err != nil { /* fix offending field before rendering */ }","typeGuard":"func isJSONEncodable(v interface{}) bool { var b []byte; _, err := json.Marshal(v); return err == nil }","tryCatchPattern":"cfg, err := tf.HCloudClusterConfig()\nif err != nil {\n\treturn fmt.Errorf(\"hcloud cluster config unavailable: %w\", err)\n}","preventionTips":["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"],"tags":["json","serialization","hetzner","kops"],"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"}