zincsearch/zincsearch · error

ErrorTypeIllegalArgumentException

ErrorTypeIllegalArgumentException

Error message

[multi_match] unknown operator %s

What it means

MultiMatchQuery validates the operator string supplied in the multi_match query body. Only "OR" and "AND" (case-sensitive) map to bluge match operators; anything else is rejected as an illegal argument. This guards against invalid operator values being passed down to the bluge search layer.

Source

Thrown at pkg/uquery/query/multi_match.go:74

			// return nil, errors.New(errors.ErrorTypeParsingException, fmt.Sprintf("[multi_match] unknown field [%s]", k))
		}
	}

	var zer *analysis.Analyzer
	if value.Analyzer != "" {
		zer, _ = zincanalysis.QueryAnalyzer(analyzers, value.Analyzer)
	}

	var operator bluge.MatchQueryOperator = bluge.MatchQueryOperatorOr
	if value.Operator != "" {
		op := strings.ToUpper(value.Operator)
		switch op {
		case "OR":
			operator = bluge.MatchQueryOperatorOr
		case "AND":
			operator = bluge.MatchQueryOperatorAnd
		default:
			return nil, errors.New(errors.ErrorTypeIllegalArgumentException, fmt.Sprintf("[multi_match] unknown operator %s", op))
		}
	}

	subq := bluge.NewBooleanQuery()
	if value.MinimumShouldMatch != nil {
		minValue, err := zutils.CalculateMin(len(value.Fields), value.MinimumShouldMatch)
		if err != nil {
			return nil, errors.New(errors.ErrorTypeXContentParseException, fmt.Sprintf("[multi_match] unsupported MinimumShouldMatch value: %v", err))
		}
		subq.SetMinShould(minValue) // lgtm[go/hardcoded-credentials]
	}
	if value.Boost >= 0 {
		subq.SetBoost(value.Boost)
	}
	for _, field := range value.Fields {
		subqq := bluge.NewMatchQuery(value.Query).SetField(field).SetOperator(operator)
		if zer != nil {
			subqq.SetAnalyzer(zer)

View on GitHub (pinned to dd2f8afd65)

Solutions

  1. Set the operator to the exact uppercase string "OR" or "AND" in the multi_match body
  2. Trim/uppercase the operator value client-side before sending
  3. Check the request JSON for stray whitespace or casing in the operator field
  4. Omit the operator field entirely to use the default

Example fix

// before
{"multi_match": {"query": "foo", "fields": ["title"], "operator": "or"}}
// after
{"multi_match": {"query": "foo", "fields": ["title"], "operator": "OR"}}
Defensive patterns

Strategy: validation

Validate before calling

op, _ := body["operator"].(string)
if op != "" && op != "OR" && op != "AND" {
    return fmt.Errorf("operator must be OR or AND, got %q", op)
}

Type guard

func isValidOperator(v interface{}) bool {
    s, ok := v.(string)
    return !ok || s == "OR" || s == "AND"
}

Try / catch

q, err := uquery.Query(body)
if err != nil {
    var e *errors.Error
    if errors.As(err, &e) && e.Type == errors.ErrorTypeIllegalArgumentException {
        // fix operator and retry
    }
}

Prevention

When it happens

Trigger: Calling MultiMatchQuery (via Query / ParseQueryDSL) with a multi_match body whose "operator" field is anything other than the exact strings "OR" or "AND" — e.g. "or", "and", "or " with whitespace, "SHOULD", or a misspelling.

Common situations: Copied ES DSL with lowercase operator "or"; dynamically built queries injecting user input into operator; typos like "ANND"; clients that default to Go-style naming instead of ES upper-case constants.

Related errors


AI-assisted analysis of zincsearch/zincsearch@dd2f8afd65 (2026-09-03). Data as JSON: /api/errors/80428233bfda2394. Report an issue: GitHub.