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

  1. Check both operand kinds before running contains: use `type` in yq (e.g. `.a | type`) to confirm map/seq/scalar on each side
  2. If checking membership, put the array/map on the LHS: `(.fruits | contains(["apple"]))` not `"apple" contains .fruits`
  3. For substring checks on a string use `test()`/`match` instead of `contains` when the other side is not a string
  4. 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

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


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