mikefarah/yq · error
strings cannot be subtracted
Error message
strings cannot be subtracted
What it means
yq refuses to subtract strings: unlike jq (which errors differently) or some shells, `-` on `!!str` operands has no meaning in yq, so subtractScalars returns this error whenever the resolved lhs tag is `!!str` and the value is not being treated as a datetime. Note the asymmetry in the message: it is raised from the subtract path even though the text says 'subtracted'.
Source
Thrown at pkg/yqlib/operator_subtract.go:97
lhsIsCustom = true
}
if !strings.HasPrefix(rhsTag, "!!") {
// custom tag - we have to have a guess
rhsTag = rhs.guessTagFromCustomType()
}
isDateTime := lhsTag == "!!timestamp"
// if the lhs is a string, it might be a timestamp in a custom format.
if lhsTag == "!!str" && context.GetDateTimeLayout() != time.RFC3339 {
_, err := parseDateTime(context.GetDateTimeLayout(), lhs.Value)
isDateTime = err == nil
}
if isDateTime {
return subtractDateTime(context.GetDateTimeLayout(), target, lhs, rhs)
} else if lhsTag == "!!str" {
return fmt.Errorf("strings cannot be subtracted")
} else if lhsTag == "!!int" && rhsTag == "!!int" {
format, lhsNum, err := parseInt64(lhs.Value)
if err != nil {
return err
}
_, rhsNum, err := parseInt64(rhs.Value)
if err != nil {
return err
}
result := lhsNum - rhsNum
target.Tag = lhs.Tag
target.Value = fmt.Sprintf(format, result)
} else if (lhsTag == "!!int" || lhsTag == "!!float") && (rhsTag == "!!int" || rhsTag == "!!float") {
lhsNum, err := strconv.ParseFloat(lhs.Value, 64)
if err != nil {
return err
}
rhsNum, err := strconv.ParseFloat(rhs.Value, 64)View on GitHub (pinned to 8b5af0694b)
Solutions
- Convert strings to numbers first with `to_number` (or `| tonumber`-style): `(.a | to_number) - (.b | to_number)`
- Unquote the values in the source YAML so they parse as !!int/!!float
- For string manipulation use the appropriate string operators/functions (sub/split, capture, etc.), not `-`
- If the string is actually a datetime, set the right layout with the datetime layout option (via `env`/timestamp functions) so it takes the datetime path
Example fix
// before: yq '"10" - "4"' -> strings cannot be subtracted
// after
yq '("10" | to_number) - ("4" | to_number)' Defensive patterns
Strategy: type-guard
Validate before calling
tag_lhs=$(yq '.a | tag' file.yml) [ "$tag_lhs" = "!!str" ] && echo "strings cannot be subtracted; convert with to_number" && exit 1
Type guard
// Go-side guard before building the expression
func isNumericScalar(s string) bool {
_, errInt := strconv.ParseInt(s, 10, 64)
_, errFloat := strconv.ParseFloat(s, 64)
return errInt == nil || errFloat == nil
} Try / catch
null
Prevention
- Avoid quoting numbers in YAML unless intentional
- Use `to_number` on string-typed numerics before arithmetic
- Use string functions (sub/capture) instead of `-` for string manipulation
When it happens
Trigger: `yq '.name - .other'` where both fields are strings; `.a - .b` where .a is a quoted number like `"10"` (tag !!str) and no custom datetime layout applies; custom-typed nodes guessed as strings.
Common situations: YAML files with quoted numbers (e.g. version: "1.2") that the user expects to be numeric; attempting string 'removal' like removing a prefix (substrings are not supported by `-`); fields tagged !!str due to explicit quoting in the source document.
Related errors
- cannot split %v, can only split strings
- %v (%v) cannot be subtracted from %v
- %v cannot be added to %v
- %v (%v) cannot be subtracted from %v
- %v cannot check contained in %v
AI-assisted analysis of mikefarah/yq@8b5af0694b (2026-09-05).
Data as JSON: /api/errors/da10d8d540da97dc.
Report an issue: GitHub.