mikefarah/yq · error

%v not yet supported for contains

Error message

%v not yet supported for contains

What it means

The yq `contains` operator only supports comparing mapping, sequence, and scalar nodes. When the left-hand node's kind is none of those (e.g. an alias/anchor node kind, or an unrecognised node kind), `contains()` falls through its switch and returns this error. It is a hard 'not implemented' guard, not a data mismatch.

Source

Thrown at pkg/yqlib/operator_contains.go:92

}

func contains(lhs *CandidateNode, rhs *CandidateNode) (bool, error) {
	switch lhs.Kind {
	case MappingNode:
		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. Inspect the input node kind with `yq --debug-node-info` or print the tag (`.tag`) to see what unsupported kind the LHS holds
  2. Dereference aliases before comparing (e.g. use `(.foo // empty)` or re-parse the input) so nodes are concrete map/seq/scalar values
  3. Convert the value to a supported form first, e.g. force a scalar with `= .value` or select the concrete node instead of the anchor
  4. If it happens on legitimately supported data, upgrade yq — this guard has shrunk as more kinds gained support

Example fix

// before: contains on an aliased node
yq '.a contains "x"' <<< 'a: &val {b: x}'
// after: dereference/return the concrete value first
yq '(.a | .) contains {b: "x"}' <<< 'a: &val {b: x}'
Defensive patterns

Strategy: type-guard

Validate before calling

// check kind before running contains in a yq pipeline
yq 'select(type == "!!map" or type == "!!seq" or type == "!!str") | . contains (...)'
// in Go embedding yqlib: switch node.Kind {
// case yqlib.MappingNode, yqlib.SequenceNode, yqlib.ScalarNode: /* safe */
// default: skip contains
// }

Type guard

func containsSupported(n *yqlib.CandidateNode) bool {
	switch n.Kind {
	case yqlib.MappingNode, yqlib.SequenceNode, yqlib.ScalarNode:
		return true
	}
	return false
}

Prevention

When it happens

Trigger: Running a `contains` expression where the LHS document node has a Kind other than MappingNode, SequenceNode, or ScalarNode (e.g. an unresolved alias node, kind 0/null-kind node, or a future node kind). The error bubbles up from containsArrayElement/containsObject when an element reached via recursion has such a kind.

Common situations: Feeding yq input in a format whose decoder produces exotic node kinds (e.g. tagged/aliased nodes in YAML), piping documents where a key resolves to an alias rather than a value, or using a very old/new yq version where node kinds differ. Very rare in normal use since YAML decoders mostly emit map/seq/scalar.

Related errors


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