GoogleContainerTools/skaffold · error
marshalling old: %v
Error message
marshalling old: %v
What it means
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.
Source
Thrown at pkg/skaffold/util/util.go:232
var result []string
scanner := bufio.NewScanner(bytes.NewReader(input))
for scanner.Scan() {
if line := scanner.Text(); len(line) > 0 {
result = append(result, line)
}
}
return result
}
// CloneThroughJSON clones an `old` object into a `new` one
// using json marshalling and unmarshalling.
// Since the object can be marshalled, it's almost sure it can be
// unmarshalled. So we prefer to panic instead of returning an error
// that would create an untestable branch on the call site.
func CloneThroughJSON(old interface{}, new interface{}) {
o, err := json.Marshal(old)
if err != nil {
panic(fmt.Sprintf("marshalling old: %v", err))
}
if err := json.Unmarshal(o, new); err != nil {
panic(fmt.Sprintf("unmarshalling new: %v", err))
}
}
// CloneThroughYAML clones an `old` object into a `new` one
// using yaml marshalling and unmarshalling.
// Since the object can be marshalled, it's almost sure it can be
// unmarshalled. So we prefer to panic instead of returning an error
// that would create an untestable branch on the call site.
func CloneThroughYAML(old interface{}, new interface{}) {
contents, err := yaml.Marshal(old)
if err != nil {
panic(fmt.Sprintf("marshalling old: %v", err))
}
if err := yaml.Unmarshal(contents, new); err != nil {
panic(fmt.Sprintf("unmarshalling new: %v", err))View on GitHub (pinned to a1189de023)
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
Example fix
// before
type Config struct {
stop chan struct{}
}
CloneThroughJSON(cfg, ©) // panics: marshalling old
// after
type Config struct {
stop chan struct{} `json:"-"`
}
CloneThroughJSON(cfg, ©) Defensive patterns
Strategy: type-guard
Validate before calling
func jsonSerializable(v interface{}) error {
var b bytes.Buffer
return json.NewEncoder(&b).Encode(v)
} Type guard
func canMarshalJSON(v interface{}) (ok bool) {
defer func() { ok = recover() == nil }()
_, err := json.Marshal(v)
return err == nil
} Try / catch
func cloneSafe(old, new interface{}) (err error) {
defer func() { if r := recover(); r != nil { err = fmt.Errorf("clone failed: %v", r) } }()
util.CloneThroughJSON(old, new)
return nil
} Prevention
- 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
When it happens
Trigger: Passing a value to CloneThroughJSON that json.Marshal cannot encode — channels, funcs, cyclic pointer graphs, or types with unsupported fields and no MarshalJSON.
Common situations: 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.
Related errors
- unmarshalling new: %v
- marshalling event: %w
- unknown panic
- marshalling configuration: %w
- marshaling new config: %w
AI-assisted analysis of GoogleContainerTools/skaffold@a1189de023 (2026-09-05).
Data as JSON: /api/errors/a466b0e33f27c3f6.
Report an issue: GitHub.