usememos/memos · error
matches requires a target
Error message
matches requires a target
What it means
buildMatchesCondition compiles CEL's matches() (regex match) and requires a receiver target, i.e. field.matches(pattern). The CEL AST for a global function call with no target has call.Target == nil, and the parser has no way to know which column to match, so it fails immediately.
Source
Thrown at internal/filter/parser.go:347
}
value, err := getConstValue(call.Args[0])
if err != nil {
return nil, errors.Wrap(err, "text match only supports literal arguments")
}
str, ok := value.(string)
if !ok {
return nil, errors.New("text match argument must be a string")
}
return &TextMatchCondition{
Field: targetName,
Mode: mode,
Value: str,
}, nil
}
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 {View on GitHub (pinned to 14d757ce1f)
Solutions
- Use the receiver form: content.matches("^TODO")
- Check filter templates for accidental deletion of the field name before the dot
- Pre-parse the CEL expression to confirm the call has a target before submitting
Example fix
// before
matches("^TODO")
// after
content.matches("^TODO") Defensive patterns
Strategy: validation
Validate before calling
// Reject global-style matches() before submission
if (/(^|[\s&|(])matches\s*\(/.test(filter)) {
throw new Error('matches() must be called on a field: field.matches("pattern")');
} Prevention
- Always write matches() in receiver form: field.matches("pattern")
- When templating filters, lint that every function call has a dotted receiver
- Document the receiver form prominently in filter help text
When it happens
Trigger: A filter that calls matches as a global function: matches("^TODO") instead of the receiver form content.matches("^TODO"). This typically happens when filter strings are assembled incorrectly or a macro/variable substitution drops the field prefix.
Common situations: Template-based filter builders that prepend/append fragments and accidentally emit matches() without its receiver; converting a contains() call and forgetting to keep the field.
Related errors
- filter must evaluate to a boolean value
- unsupported top-level expression
- logical AND expects two arguments
- logical OR expects two arguments
- logical NOT expects one argument
AI-assisted analysis of usememos/memos@14d757ce1f (2026-08-15).
Data as JSON: /api/errors/6a907cffb63f72a4.
Report an issue: GitHub.