mikefarah/yq · error
%v (%v) cannot be subtracted from %v
Error message
%v (%v) cannot be subtracted from %v
What it means
When the lhs of a comparison is a scalar but the RIGHT-hand side is not a scalar (e.g. it is a map or array), yq cannot compare them and reports this error. The message text says 'cannot be subtracted' for historical reasons (the format string is shared), but the operator is actually the comparison (<, <=, >, >=). The error includes the rhs tag and path plus the lhs tag to pinpoint the mismatch.
Source
Thrown at pkg/yqlib/operator_compare.go:41
if lhs == nil && rhs == nil {
owner := &CandidateNode{}
return createBooleanCandidate(owner, prefs.OrEqual), nil
} else if lhs == nil {
log.Debugf("lhs nil, but rhs is not")
return createBooleanCandidate(rhs, false), nil
} else if rhs == nil {
log.Debugf("rhs nil, but rhs is not")
return createBooleanCandidate(lhs, false), nil
}
switch lhs.Kind {
case MappingNode:
return nil, fmt.Errorf("maps not yet supported for comparison")
case SequenceNode:
return nil, fmt.Errorf("arrays not yet supported for comparison")
default:
if rhs.Kind != ScalarNode {
return nil, fmt.Errorf("%v (%v) cannot be subtracted from %v", rhs.Tag, rhs.GetNicePath(), lhs.Tag)
}
target := lhs.CopyWithoutContent()
boolV, err := compareScalars(context, prefs, lhs, rhs)
return createBooleanCandidate(target, boolV), err
}
}
}
func compareDateTime(layout string, prefs compareTypePref, lhs *CandidateNode, rhs *CandidateNode) (bool, error) {
lhsTime, err := parseDateTime(layout, lhs.Value)
if err != nil {
return false, err
}
rhsTime, err := parseDateTime(layout, rhs.Value)
if err != nil {
return false, errView on GitHub (pinned to 8b5af0694b)
Solutions
- Check what the rhs resolves to: `yq '.items | type' file.yaml`, and navigate to the intended scalar field.
- If testing membership, use `contains` or `any`: `(.items | any(. == 3))` instead of `3 < .items`.
- If comparing counts, wrap arrays in `length`: `.count >= (.items | length)`.
- Verify input schema (e.g. with `yq 'paths(type == "!!seq")'`) if the field was expected to be a scalar.
Example fix
# before yq '.replicas > .servers' file.yaml # .servers is an array # after yq '.replicas > (.servers | length)' file.yaml
Defensive patterns
Strategy: validation
Validate before calling
# confirm both comparison operands are scalars before running: yq -e '((.replicas | type) == "!!scalar" and (.servers | type) == "!!scalar")' file.yaml || echo "non-scalar operand"
Type guard
// yq expression guard: assert rhs is scalar // yq '. as $l | .servers as $r | select(($r | tag) == "!!int" or ($r | tag) == "!!float" or ($r | tag) == "!!str") | $l.replicas > $r' file.yaml
Prevention
- Resolve rhs paths to leaf scalars; print them with the expression first
- Wrap array/map operands in length or index into them
- Use contains/any for 'is it in the list' semantics
- Validate input schema when fields may change type
When it happens
Trigger: Expressions like `yq '3 < .tags' file.yaml` or `yq '.count >= .items'` where the rhs path resolves to a non-scalar (MappingNode or SequenceNode) while the lhs is a scalar. Also triggered via crossFunction when one side of a cross-product comparison resolves to a map/array.
Common situations: Typos in the rhs path that land on a parent object instead of a leaf field; schema changes where a field became an array; comparing a scalar against a whole list intending 'is it in the list' (should be `any`/`contains`); accidentally comparing across document types.
Related errors
- maps not yet supported for comparison
- arrays not yet supported for comparison
- %v not yet supported for comparison
- %v cannot check contained in %v
- from entries only runs against arrays
AI-assisted analysis of mikefarah/yq@8b5af0694b (2026-09-05).
Data as JSON: /api/errors/2e939dea79556991.
Report an issue: GitHub.