{"record":{"id":"773ab24cc59fbaf1","repo":"mikefarah/yq","slug":"bad-expression-could-not-find-matching-773ab2","errorCode":null,"errorMessage":"bad expression, could not find matching `)`","messagePattern":"bad expression, could not find matching `\\)`","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/yqlib/expression_postfix.go","lineNumber":34,"sourceCode":"func newExpressionPostFixer() expressionPostFixer {\n\treturn &expressionPostFixerImpl{}\n}\n\nfunc popOpToResult(opStack []*token, result []*Operation) ([]*token, []*Operation) {\n\tvar newOp *token\n\topStack, newOp = opStack[0:len(opStack)-1], opStack[len(opStack)-1]\n\tlog.Debugf(\"popped %v from opstack to results\", newOp.toString(true))\n\treturn opStack, append(result, newOp.Operation)\n}\n\nfunc validateNoOpenTokens(token *token) error {\n\tswitch token.TokenType {\n\tcase openCollect:\n\t\treturn fmt.Errorf((\"bad expression, could not find matching `]`\"))\n\tcase openCollectObject:\n\t\treturn fmt.Errorf((\"bad expression, could not find matching `}`\"))\n\tcase openBracket:\n\t\treturn fmt.Errorf((\"bad expression, could not find matching `)`\"))\n\t}\n\treturn nil\n}\n\nfunc (p *expressionPostFixerImpl) ConvertToPostfix(infixTokens []*token) ([]*Operation, error) {\n\tvar result []*Operation\n\t// surround the whole thing with brackets\n\tvar opStack = []*token{{TokenType: openBracket}}\n\tvar tokens = append(infixTokens, &token{TokenType: closeBracket})\n\n\tfor _, currentToken := range tokens {\n\t\tlog.Debugf(\"postfix processing currentToken %v\", currentToken.toString(true))\n\t\tswitch currentToken.TokenType {\n\t\tcase openBracket, openCollect, openCollectObject:\n\t\t\topStack = append(opStack, currentToken)\n\t\t\tlog.Debugf(\"put %v onto the opstack\", currentToken.toString(true))\n\t\tcase closeCollect, closeCollectObject:\n\t\t\tvar opener tokenType = openCollect","sourceCodeStart":16,"sourceCodeEnd":52,"githubUrl":"https://github.com/mikefarah/yq/blob/8b5af0694bb82b41d4ae180fac9972029066f90a/pkg/yqlib/expression_postfix.go#L16-L52","documentation":"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.","triggerScenarios":"Running `yq '(.a + .b' file.yml` — any `(` without its matching `)`, common when parentheses are dropped by bad shell quoting or nested subexpressions.","commonSituations":"Complex arithmetic/filter expressions in shell scripts where quotes were lost, parenthesised selects like `select(.x == 1)` missing the final `)`.","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"],"exampleFix":"// before\nyq '(.a + .b' file.yml\n// after\nyq '(.a + .b)' file.yml","handlingStrategy":"validation","validationCode":"depth := strings.Count(expr, \"(\") - strings.Count(expr, \")\")\nif depth != 0 {\n    return fmt.Errorf(\"unbalanced parentheses in expression %q\", expr)\n}","typeGuard":null,"tryCatchPattern":"out, err := runYq(expr, file)\nif err != nil && strings.Contains(err.Error(), \"could not find matching `)`\") {\n    return fmt.Errorf(\"unclosed ( in expression %q\", expr)\n}","preventionTips":["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"],"tags":["expression","bracket","syntax"],"backgroundTag":"unclosed-bracket-expression","analyzedSha":"8b5af0694bb82b41d4ae180fac9972029066f90a","analyzedAt":"2026-09-05T10:57:22.766Z","contentChangedAt":"2026-09-05T10:57:22.766Z","schemaVersion":2},"datasetVersion":"2026-09-12T17:17:11.597Z"}