{"record":{"id":"13497b784f3f7d13","repo":"mikefarah/yq","slug":"bad-path-expression-got-close-collect-brackets-wi","errorCode":null,"errorMessage":"bad path expression, got close collect brackets without matching opening bracket","messagePattern":"bad path expression, got close collect brackets without matching opening bracket","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/yqlib/expression_postfix.go","lineNumber":67,"sourceCode":"\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\n\t\t\tvar collectOperator = collectOpType\n\t\t\tif currentToken.TokenType == closeCollectObject {\n\t\t\t\topener = openCollectObject\n\t\t\t\tcollectOperator = collectObjectOpType\n\t\t\t}\n\n\t\t\tfor len(opStack) > 0 && opStack[len(opStack)-1].TokenType != opener {\n\t\t\t\tmissingClosingTokenErr := validateNoOpenTokens(opStack[len(opStack)-1])\n\t\t\t\tif missingClosingTokenErr != nil {\n\t\t\t\t\treturn nil, missingClosingTokenErr\n\t\t\t\t}\n\t\t\t\topStack, result = popOpToResult(opStack, result)\n\t\t\t}\n\t\t\tif len(opStack) == 0 {\n\t\t\t\treturn nil, errors.New(\"bad path expression, got close collect brackets without matching opening bracket\")\n\t\t\t}\n\t\t\t// now we should have [ as the last element on the opStack, get rid of it\n\t\t\topStack = opStack[0 : len(opStack)-1]\n\t\t\tlog.Debugf(\"deleting open bracket from opstack\")\n\n\t\t\t//and append a collect to the result\n\n\t\t\t// hack - see if there's the optional traverse flag\n\t\t\t// on the close op - move it to the traverse array op\n\t\t\t// allows for .[\"cat\"]?\n\t\t\tprefs := traversePreferences{}\n\t\t\tcloseTokenMatch := currentToken.Match\n\t\t\tif closeTokenMatch[len(closeTokenMatch)-1:] == \"?\" {\n\t\t\t\tprefs.OptionalTraverse = true\n\t\t\t}\n\t\t\tresult = append(result, &Operation{OperationType: collectOperator})\n\t\t\tlog.Debugf(\"put collect onto the result\")\n\t\t\tif opener != openCollect {","sourceCodeStart":49,"sourceCodeEnd":85,"githubUrl":"https://github.com/mikefarah/yq/blob/8b5af0694bb82b41d4ae180fac9972029066f90a/pkg/yqlib/expression_postfix.go#L49-L85","documentation":"yq compiles expressions to postfix (RPN) using a shunting-yard algorithm that tracks open/close bracket pairs. A `]` (close collect bracket) arrived while the operator stack had no matching `[`, so the expression is structurally unbalanced. The library throws this rather than guessing intent.","triggerScenarios":"Evaluating any yq expression containing `]` without a preceding `[`, e.g. `yq '.foo]'`, `yq 'select(.a)]'`, or a programmatically built expression string that lost its opening `[` (often via shell quoting stripping brackets or string interpolation).","commonSituations":"Shell quoting issues where `[` is treated as a glob/stripped by the shell; templating a yq expression from variables where the array-collect part is conditionally omitted; typos like `.items]` instead of `.items[]`.","solutions":["Fix the expression so every `]` has a matching `[` (e.g. `.items[]` not `.items]`).","Quote the expression in single quotes so the shell does not mangle brackets: yq '.a[0]'.","If generating expressions dynamically, validate bracket balance before invoking yq."],"exampleFix":"// before (unbalanced)\nyq '.items]' file.yaml\n// after\nyq '.items[]' file.yaml","handlingStrategy":"validation","validationCode":"func balanced(expr string) bool {\n    var depth int\n    for _, r := range expr {\n        switch r {\n        case '[':\n            depth++\n        case ']':\n            depth--\n            if depth < 0 {\n                return false\n            }\n        }\n    }\n    return depth == 0\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Single-quote yq expressions in shell so brackets aren't glob-expanded or stripped.","When templating expressions, assert bracket balance before invoking yq.","Prefer --expression '<expr>' to positional args in scripts for predictable parsing."],"tags":["expression","parser","brackets"],"backgroundTag":"unbalanced-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"}