mikefarah/yq · error
%v cannot check contained in %v
Error message
%v cannot check contained in %v
What it means
`containsWithNodes` requires both sides of the `contains` operator to be the same node Kind (map vs map, seq vs seq, scalar vs scalar). When the LHS and RHS kinds differ it immediately returns this error naming the two tags. Note it compares Kinds, and reports Tags in the message, so e.g. checking a scalar contained in an array at top level triggers it.
Source
Thrown at pkg/yqlib/operator_contains.go:97
return containsObject(lhs, rhs)
case SequenceNode:
return containsArray(lhs, rhs)
case ScalarNode:
if rhs.Kind != ScalarNode || lhs.Tag != rhs.Tag {
return false, nil
}
if lhs.Tag == "!!null" {
return rhs.Tag == "!!null", nil
}
return containsScalars(lhs, rhs)
}
return false, fmt.Errorf("%v not yet supported for contains", lhs.Tag)
}
func containsWithNodes(_ *dataTreeNavigator, _ Context, lhs *CandidateNode, rhs *CandidateNode) (*CandidateNode, error) {
if lhs.Kind != rhs.Kind {
return nil, fmt.Errorf("%v cannot check contained in %v", rhs.Tag, lhs.Tag)
}
result, err := contains(lhs, rhs)
if err != nil {
return nil, err
}
return createBooleanCandidate(lhs, result), nil
}
View on GitHub (pinned to 8b5af0694b)
Solutions
- Check both operand kinds before running contains: use `type` in yq (e.g. `.a | type`) to confirm map/seq/scalar on each side
- If checking membership, put the array/map on the LHS: `(.fruits | contains(["apple"]))` not `"apple" contains .fruits`
- For substring checks on a string use `test()`/`match` instead of `contains` when the other side is not a string
- Guard heterogeneous documents: `select(type == "!!seq") | contains([...])` so only sequence documents are compared
Example fix
// before: kinds mismatch, error
yq '"apple" contains ["app"]'
// after: array on LHS, matching kinds
yq '["apple"] contains ["app"]' # or use test for substrings:
yq '"apple" | test("app")' Defensive patterns
Strategy: validation
Validate before calling
# ensure both sides have the same type before contains yq 'select((.a | type) == ($b | type)) | .a contains $b' # or in shell, pre-check: # yq '.a | type' file.yml -> must equal type of RHS
Type guard
func sameKind(a, b *yqlib.CandidateNode) bool { return a.Kind == b.Kind } Try / catch
// wrap the evaluation and inspect the message
out, err := eval(expr)
if err != nil && strings.Contains(err.Error(), "cannot check contained in") {
// fall back to test() for string substring checks
} Prevention
- Remember yq semantics: array/map goes on the LHS of contains
- Use test() for substring matching on strings, not contains
- Guard heterogeneous documents with select(type == "!!seq") style filters
- Check `type` of both operands in an interactive yq run before scripting
When it happens
Trigger: Running expressions like `'"abc" contains ["a"]'`, `'.a contains "x"'` where .a is a map but the RHS is a scalar, or `'[] contains {}'` — any `contains` where lhs.Kind != rhs.Kind at the top level of the cross-function.
Common situations: Hand-writing a contains filter assuming substring semantics on a non-string, or checking array membership with the LHS/RHS reversed (users often write `item contains array` when yq expects `array contains item`). Also common when a field is sometimes a string and sometimes an array across documents.
Related errors
- %v (%v) cannot be subtracted from %v
- %v not yet supported for contains
- from entries only runs against arrays
- cannot substitute with %v, can only substitute strings. Hint
- only arrays are supported for flatten
AI-assisted analysis of mikefarah/yq@8b5af0694b (2026-09-05).
Data as JSON: /api/errors/c19479232b6cc3cd.
Report an issue: GitHub.