GoogleContainerTools/skaffold · error

unmarshalling new: %v

Error message

unmarshalling new: %v

What it means

CloneThroughJSON's second panic fires when the JSON produced from `old` cannot be unmarshalled into `new`. The library assumes this is near-impossible (same data round-trips), so it panics instead of returning an error, keeping call sites simple.

Source

Thrown at pkg/skaffold/util/util.go:235

		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 `new` is a pointer to a type structurally compatible with `old`
  2. Re-align field names/types after a refactor so the JSON round-trip is lossless
  3. Add a regression test that clones the struct and compares the result to the original

Example fix

// before
var copy Config
CloneThroughJSON(cfg, copy) // copy not a pointer; unmarshal fails
// after
var copy Config
CloneThroughJSON(cfg, &copy)
Defensive patterns

Strategy: type-guard

Validate before calling

func cloneCompatible(old, new interface{}) error {
  ob, err := json.Marshal(old)
  if err != nil { return err }
  return json.Unmarshal(ob, new)
}

Type guard

func isPointerToStruct(v interface{}) bool {
  rv := reflect.ValueOf(v)
  return rv.Kind() == reflect.Ptr && rv.Elem().Kind() == reflect.Struct
}

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: Calling CloneThroughJSON(old, new) where `new` has a type incompatible with `old`'s JSON shape — e.g. cloning into a struct with different field types, a non-pointer destination, or mismatched numeric/string fields.

Common situations: Refactoring one of the two types so field types diverge (string vs int, object vs slice); passing a value instead of a pointer for `new`; cloning between unrelated structs.

Related errors


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