mikefarah/yq · error
bad expression, could not find matching `)`
Error message
bad expression, could not find matching `)`
What it means
After the infix-to-postfix conversion finished, validateNoOpenTokens found an openCollect token still on the operator stack — a '[' or (per the sibling case) '(' that was never closed. The message names ')' because the conversion cannot complete a parenthesised group, so the expression is syntactically unbalanced and is rejected before evaluation.
Source
Thrown at pkg/yqlib/expression_postfix.go:34
func newExpressionPostFixer() expressionPostFixer {
return &expressionPostFixerImpl{}
}
func popOpToResult(opStack []*token, result []*Operation) ([]*token, []*Operation) {
var newOp *token
opStack, newOp = opStack[0:len(opStack)-1], opStack[len(opStack)-1]
log.Debugf("popped %v from opstack to results", newOp.toString(true))
return opStack, append(result, newOp.Operation)
}
func validateNoOpenTokens(token *token) error {
switch token.TokenType {
case openCollect:
return fmt.Errorf(("bad expression, could not find matching `]`"))
case openCollectObject:
return fmt.Errorf(("bad expression, could not find matching `}`"))
case openBracket:
return fmt.Errorf(("bad expression, could not find matching `)`"))
}
return nil
}
func (p *expressionPostFixerImpl) ConvertToPostfix(infixTokens []*token) ([]*Operation, error) {
var result []*Operation
// surround the whole thing with brackets
var opStack = []*token{{TokenType: openBracket}}
var tokens = append(infixTokens, &token{TokenType: closeBracket})
for _, currentToken := range tokens {
log.Debugf("postfix processing currentToken %v", currentToken.toString(true))
switch currentToken.TokenType {
case openBracket, openCollect, openCollectObject:
opStack = append(opStack, currentToken)
log.Debugf("put %v onto the opstack", currentToken.toString(true))
case closeCollect, closeCollectObject:
var opener tokenType = openCollectView on GitHub (pinned to 8b5af0694b)
Solutions
- Add the matching `)` to close the group (e.g. `(.a + .b)`)
- Single-quote the expression in shell so parentheses survive
- Balance-check parentheses in generated/template expressions
Example fix
// before yq '(.a + .b' file.yml // after yq '(.a + .b)' file.yml
Defensive patterns
Strategy: validation
Validate before calling
depth := strings.Count(expr, "(") - strings.Count(expr, ")")
if depth != 0 {
return fmt.Errorf("unbalanced parentheses in expression %q", expr)
} Try / catch
out, err := runYq(expr, file)
if err != nil && strings.Contains(err.Error(), "could not find matching `)`") {
return fmt.Errorf("unclosed ( in expression %q", expr)
} Prevention
- Single-quote expressions containing parentheses in bash/zsh
- Format nested expressions with one paren per level to make imbalance obvious
- Validate parentheses in CI before running generated expressions
When it happens
Trigger: Running `yq '(.a + .b' file.yml` — any `(` without its matching `)`, common when parentheses are dropped by bad shell quoting or nested subexpressions.
Common situations: Complex arithmetic/filter expressions in shell scripts where quotes were lost, parenthesised selects like `select(.x == 1)` missing the final `)`.
Related errors
- bad expression, could not find matching `]`
- bad expression, could not find matching `}`
- bad expression - probably missing close bracket on %v
- '%v' expects 1 arg but received none
- '%v' expects 2 args but there is %v
AI-assisted analysis of mikefarah/yq@8b5af0694b (2026-09-05).
Data as JSON: /api/errors/773ab24cc59fbaf1.
Report an issue: GitHub.