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

  1. Ensure the type passed to CloneThroughJSON is fully JSON-serializable (no channels/funcs/cycles)
  2. Add MarshalJSON to the offending type or tag problematic fields with `json:"-"`
  3. Validate with a test calling CloneThroughJSON on the struct to surface failures early

Example fix

// before
type Config struct {
  stop chan struct{}
}
CloneThroughJSON(cfg, &copy) // panics: marshalling old
// after
type Config struct {
  stop chan struct{} `json:"-"`
}
CloneThroughJSON(cfg, &copy)
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

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


AI-assisted analysis of GoogleContainerTools/skaffold@a1189de023 (2026-09-05). Data as JSON: /api/errors/a466b0e33f27c3f6. Report an issue: GitHub.