mikefarah/yq · error

bad expression, could not find matching `]`

Error message

bad expression, could not find matching `]`

What it means

During infix-to-postfix conversion, validateNoOpenTokens detects an unclosed openCollect token ('[') at the end of the token stream. This means a collect/array bracket was opened but never closed, so the expression cannot be evaluated.

Source

Thrown at pkg/yqlib/expression_postfix.go:30

type expressionPostFixerImpl struct {
}

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:

View on GitHub (pinned to 8b5af0694b)

Solutions

  1. Add the matching `]` to close the collect (e.g. `[.a, .b]`)
  2. Quote the expression properly so the shell doesn't eat brackets (single quotes)
  3. If using multi-line expressions, verify the final line closes all brackets

Example fix

// before
yq '[.a' file.yml
// after
yq '[.a]' file.yml
Defensive patterns

Strategy: validation

Validate before calling

// naive balance check before invoking yq
depth := 0
for _, r := range expr {
    switch r {
    case '[': depth++
    case ']': depth--
    }
    if depth < 0 { break }
}
if depth != 0 {
    return fmt.Errorf("unbalanced [ ] 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

When it happens

Trigger: Running `yq '[.a' file.yml` or any expression with `[` without matching `]`, e.g. `yq '.a[.b'` or an incomplete map/collect in a select.

Common situations: Hand-written collect expressions in CI scripts, truncated expressions from shell quoting, forgetting to close a multi-line expression.

Related errors


AI-assisted analysis of mikefarah/yq@8b5af0694b (2026-09-05). Data as JSON: /api/errors/aa1d0202c6d4e762. Report an issue: GitHub.