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

  1. 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.
  2. Update to the latest yq release; if reproducible upstream, file a bug with the exact expression used (key-targeting assignment/comment expression).
  3. 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.
  4. As a workaround, avoid key-targeting forms (assign to values or use explicit map reconstruction) until fixed.
  5. 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

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


AI-assisted analysis of mikefarah/yq@8b5af0694b (2026-09-05). Data as JSON: /api/errors/22b446a27544f560. Report an issue: GitHub.