{"record":{"id":"a466b0e33f27c3f6","repo":"GoogleContainerTools/skaffold","slug":"marshalling-old-v","errorCode":null,"errorMessage":"marshalling old: %v","messagePattern":"marshalling old: (.+?)","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/skaffold/util/util.go","lineNumber":232,"sourceCode":"\tvar result []string\n\tscanner := bufio.NewScanner(bytes.NewReader(input))\n\tfor scanner.Scan() {\n\t\tif line := scanner.Text(); len(line) > 0 {\n\t\t\tresult = append(result, line)\n\t\t}\n\t}\n\treturn result\n}\n\n// CloneThroughJSON clones an `old` object into a `new` one\n// using json marshalling and unmarshalling.\n// Since the object can be marshalled, it's almost sure it can be\n// unmarshalled. So we prefer to panic instead of returning an error\n// that would create an untestable branch on the call site.\nfunc CloneThroughJSON(old interface{}, new interface{}) {\n\to, err := json.Marshal(old)\n\tif err != nil {\n\t\tpanic(fmt.Sprintf(\"marshalling old: %v\", err))\n\t}\n\tif err := json.Unmarshal(o, new); err != nil {\n\t\tpanic(fmt.Sprintf(\"unmarshalling new: %v\", err))\n\t}\n}\n\n// CloneThroughYAML clones an `old` object into a `new` one\n// using yaml marshalling and unmarshalling.\n// Since the object can be marshalled, it's almost sure it can be\n// unmarshalled. So we prefer to panic instead of returning an error\n// that would create an untestable branch on the call site.\nfunc CloneThroughYAML(old interface{}, new interface{}) {\n\tcontents, err := yaml.Marshal(old)\n\tif err != nil {\n\t\tpanic(fmt.Sprintf(\"marshalling old: %v\", err))\n\t}\n\tif err := yaml.Unmarshal(contents, new); err != nil {\n\t\tpanic(fmt.Sprintf(\"unmarshalling new: %v\", err))","sourceCodeStart":214,"sourceCodeEnd":250,"githubUrl":"https://github.com/GoogleContainerTools/skaffold/blob/a1189de023efc32d4b8e11f395acc678aa555011/pkg/skaffold/util/util.go#L214-L250","documentation":"CloneThroughJSON clones an object by marshalling it to JSON; it deliberately panics on marshal failure. The doc comment explains that if an object can be marshalled it should also be unmarshallable, so errors represent unreachable branches and callers would have no testable handling anyway.","triggerScenarios":"Passing a value to CloneThroughJSON that json.Marshal cannot encode — channels, funcs, cyclic pointer graphs, or types with unsupported fields and no MarshalJSON.","commonSituations":"Cloning internal structs that gained a func or channel field in a refactor; accidentally passing an unexported-type-containing structure that fails marshalling; passing a cyclic object graph.","solutions":["Ensure the type passed to CloneThroughJSON is fully JSON-serializable (no channels/funcs/cycles)","Add MarshalJSON to the offending type or tag problematic fields with `json:\"-\"`","Validate with a test calling CloneThroughJSON on the struct to surface failures early"],"exampleFix":"// before\ntype Config struct {\n  stop chan struct{}\n}\nCloneThroughJSON(cfg, &copy) // panics: marshalling old\n// after\ntype Config struct {\n  stop chan struct{} `json:\"-\"`\n}\nCloneThroughJSON(cfg, &copy)","handlingStrategy":"type-guard","validationCode":"func jsonSerializable(v interface{}) error {\n  var b bytes.Buffer\n  return json.NewEncoder(&b).Encode(v)\n}","typeGuard":"func canMarshalJSON(v interface{}) (ok bool) {\n  defer func() { ok = recover() == nil }()\n  _, err := json.Marshal(v)\n  return err == nil\n}","tryCatchPattern":"func cloneSafe(old, new interface{}) (err error) {\n  defer func() { if r := recover(); r != nil { err = fmt.Errorf(\"clone failed: %v\", r) } }()\n  util.CloneThroughJSON(old, new)\n  return nil\n}","preventionTips":["Tag non-serializable fields (channels, funcs, sync primitives) with `json:\"-\"`","Never store cyclic references in structs destined for JSON cloning","Add round-trip clone tests to CI for cloned config types"],"tags":["json","serialization","panic","clone"],"backgroundTag":"json-marshal-unsupported-type","analyzedSha":"a1189de023efc32d4b8e11f395acc678aa555011","analyzedAt":"2026-09-05T12:09:27.064Z","contentChangedAt":"2026-09-05T12:09:27.064Z","schemaVersion":2},"datasetVersion":"2026-09-12T17:17:11.597Z"}