usememos/memos · error

matches expects exactly one argument

Error message

matches expects exactly one argument

What it means

The regex matches() translation accepts exactly one argument (the pattern). A call with zero or 2+ arguments cannot be compiled to a single SQL regex predicate, so buildMatchesCondition rejects it at parse time.

Source

Thrown at internal/filter/parser.go:362

func buildMatchesCondition(call *exprv1.Expr_Call, schema Schema) (Condition, error) {
	if call.Target == nil {
		return nil, errors.New("matches requires a target")
	}
	targetName, err := getIdentName(call.Target)
	if err != nil {
		return nil, err
	}

	field, ok := schema.Field(targetName)
	if !ok {
		return nil, errors.Errorf("unknown identifier %q", targetName)
	}
	if !field.SupportsContains {
		return nil, errors.Errorf("identifier %q does not support matches()", targetName)
	}
	if len(call.Args) != 1 {
		return nil, errors.New("matches expects exactly one argument")
	}
	value, err := getConstValue(call.Args[0])
	if err != nil {
		return nil, errors.Wrap(err, "matches only supports literal arguments")
	}
	pattern, ok := value.(string)
	if !ok {
		return nil, errors.New("matches argument must be a string")
	}
	return &RegexCondition{
		Field:   targetName,
		Pattern: pattern,
	}, nil
}

func buildValueExpr(expr *exprv1.Expr, pc parseContext) (ValueExpr, error) {
	if identName, err := getIdentName(expr); err == nil {
		// `now` is not a schema field; it folds to the frozen evaluation time.

View on GitHub (pinned to 14d757ce1f)

Solutions

  1. Pass exactly one regex pattern: content.matches("^TODO.*")
  2. Drop any flags argument; use inline (?i) in the pattern for case-insensitive matching if supported by the store's regex dialect
  3. Lint user-supplied filters with a CEL parser before calling the API

Example fix

// before
content.matches("todo", "i")

// after
content.matches("(?i)todo")
Defensive patterns

Strategy: validation

Validate before calling

// Go: quick arity lint for matches
re := regexp.MustCompile(`\.matches\((?:[^"()]|"[^"]*")*\)`)
// full validation is easier via cel.Parse + an Ast walker asserting len(args)==1

Prevention

When it happens

Trigger: content.matches() or content.matches("a", "b") in a filter expression passed to the memo filter API.

Common situations: Copy-paste from JS RegExp(text, flags) style where flags are a second argument; hand-written filters missing the pattern string.

Related errors


AI-assisted analysis of usememos/memos@14d757ce1f (2026-08-15). Data as JSON: /api/errors/298be120adc9fc14. Report an issue: GitHub.