mikefarah/yq · error
panic(err) on copier.Copy failure of traverse preferences
Error message
panic(err) on copier.Copy failure of traverse preferences
What it means
createTraversalTree builds an implicit traverse expression from a resolved path (used by assignment, comments, and append operators). When the path has a single element and targetKey is true, it copies traversePreferences with jinzhu/copier; any error from copier.Copy triggers panic(err) at operators.go:194-197. copier only fails on struct-copy incompatibilities, so in practice this is an internal invariant failure surfaced as a crash rather than a user-input error.
Source
Thrown at pkg/yqlib/operators.go:196
}
noob := owner.CreateReplacement(ScalarNode, "!!bool", valString)
if owner.IsMapKey {
noob.IsMapKey = false
noob.Key = owner
}
return noob
}
func createTraversalTree(path []interface{}, traversePrefs traversePreferences, targetKey bool) *ExpressionNode {
if len(path) == 0 {
return &ExpressionNode{Operation: &Operation{OperationType: selfReferenceOpType}}
} else if len(path) == 1 {
lastPrefs := traversePrefs
if targetKey {
err := copier.Copy(&lastPrefs, traversePrefs)
if err != nil {
panic(err)
}
lastPrefs.IncludeMapKeys = true
lastPrefs.DontIncludeMapValues = true
}
return &ExpressionNode{Operation: &Operation{OperationType: traversePathOpType, Preferences: lastPrefs, Value: path[0], StringValue: fmt.Sprintf("%v", path[0])}}
}
return &ExpressionNode{
Operation: &Operation{OperationType: shortPipeOpType},
LHS: createTraversalTree(path[0:1], traversePrefs, false),
RHS: createTraversalTree(path[1:], traversePrefs, targetKey),
}
}
View on GitHub (pinned to 8b5af0694b)
Solutions
- Verify you are running an unmodified, version-matched yq build; rebuild from a clean checkout (go build -o yq .) to rule out a patched traversePreferences struct.
- Update to the latest yq release; if reproducible upstream, file a bug with the exact expression used (key-targeting assignment/comment expression).
- If you fork yqlib, ensure any new fields in traversePreferences are copy-compatible with jinzhu/copier (exported, basic types) or implement a Copy() method copier will use.
- As a workaround, avoid key-targeting forms (assign to values or use explicit map reconstruction) until fixed.
- In library code, wrap calls in recover() if you must host yqlib inside a long-running process, since this is a panic not an error return.
Example fix
// before (fork with new field)
type traversePreferences struct { ... ; OnKey func(*CandidateNode) bool }
// after
type traversePreferences struct { ... } // keep fields copy-compatible, or add:
func (p traversePreferences) Copy() traversePreferences { p2 := p; /* manual copy */; return p2 } Defensive patterns
Strategy: try-catch
Validate before calling
// Go host: confirm stock build (unmodified traversePreferences) before use // no user-side data validation can prevent this; verify binary integrity instead: // go build -o yq . && ./yq --version # matches upstream release
Type guard
func prefsCopyCompatible(v reflect.Value) bool {
t := v.Type()
for i := 0; i < t.NumField(); i++ {
f := t.Field(i)
if !f.IsExported() || f.Type.Kind() == reflect.Func || f.Type.Kind() == reflect.Chan {
return false
}
}
return true
} Try / catch
func runKeyAssignment(expr string) (err error) {
defer func() { if r := recover(); r != nil { err = fmt.Errorf("createTraversalTree panic: %v", r) } }()
// ... invoke yqlib setPathOperator/applyAssignment ...
return nil
} Prevention
- Run stock yq builds; avoid forks that add func/unexported fields to traversePreferences
- Keep yqlib and vendored copier versions in sync when upgrading
- Always recover() around embedded yqlib calls in long-running processes
- If a panic reproduces on a stock build with a key-targeting expression, report it upstream with the expression
When it happens
Trigger: Calling paths that reach createTraversalTree with targetKey=true and a single-element path: setPathOperator/applyAssignment via key-only assignment (e.g. `yq '.a.b key = ...'`/keys operations), applyPropertyComments/DeeplyAssign comment application on a map key, arrayAppend, or getPathToUse — i.e. essentially any operation that mutates map *keys* rather than values, if copier encounters incompatible fields.
Common situations: Custom builds where traversePreferences gained fields copier cannot copy (e.g. func or unexported/chan fields added by embedding or forks); version mismatches after upgrading yqlib with vendored forks; practically never from user YAML input itself.
Related errors
- panic(err) on parseInt64 failure while sorting !!int values
- panic(err) on ParseFloat failure while sorting numeric value
- no support for input format
- aborted
- unrecognised type :( %v
AI-assisted analysis of mikefarah/yq@8b5af0694b (2026-09-05).
Data as JSON: /api/errors/22b446a27544f560.
Report an issue: GitHub.