{"record":{"id":"59a44221b06569d1","repo":"usememos/memos","slug":"text-match-expects-exactly-one-argument","errorCode":null,"errorMessage":"text match expects exactly one argument","messagePattern":"text match expects exactly one argument","errorType":"validation","errorClass":null,"httpStatus":400,"severity":"error","filePath":"internal/filter/parser.go","lineNumber":328,"sourceCode":"\nfunc buildTextMatchCondition(call *exprv1.Expr_Call, schema Schema, mode TextMatchMode) (Condition, error) {\n\tif call.Target == nil {\n\t\treturn nil, errors.New(\"text match requires a target\")\n\t}\n\ttargetName, err := getIdentName(call.Target)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tfield, ok := schema.Field(targetName)\n\tif !ok {\n\t\treturn nil, errors.Errorf(\"unknown identifier %q\", targetName)\n\t}\n\tif !field.SupportsContains {\n\t\treturn nil, errors.Errorf(\"identifier %q does not support text matching\", targetName)\n\t}\n\tif len(call.Args) != 1 {\n\t\treturn nil, errors.New(\"text match expects exactly one argument\")\n\t}\n\tvalue, err := getConstValue(call.Args[0])\n\tif err != nil {\n\t\treturn nil, errors.Wrap(err, \"text match only supports literal arguments\")\n\t}\n\tstr, ok := value.(string)\n\tif !ok {\n\t\treturn nil, errors.New(\"text match argument must be a string\")\n\t}\n\treturn &TextMatchCondition{\n\t\tField: targetName,\n\t\tMode:  mode,\n\t\tValue: str,\n\t}, nil\n}\n\nfunc buildMatchesCondition(call *exprv1.Expr_Call, schema Schema) (Condition, error) {\n\tif call.Target == nil {","sourceCodeStart":310,"sourceCodeEnd":346,"githubUrl":"https://github.com/usememos/memos/blob/14d757ce1fb31c78590f374bc042f8dbedbc20d7/internal/filter/parser.go#L310-L346","documentation":"The CEL filter parser rejects a text-matching call (contains/endsWith/startsWith-style text match) whose argument count is not exactly one. internal/filter/parser.go builds a TextMatchCondition only for calls of the form field.textMatch(literal), and arity other than 1 has no valid SQL translation. This is a compile-time validation of the user-supplied filter string, not a runtime data error.","triggerScenarios":"A filter expression like content.contains() (zero args) or content.contains(\"a\", \"b\") (two args) sent to the memo list/filter API that accepts CEL filters. The parser reaches buildTextMatchCondition with len(call.Args) != 1 and returns the error before any SQL is generated.","commonSituations":"Hand-building filter strings in a script or client SDK and forgetting the argument, passing extra locale/option arguments copied from another API (e.g. JS String.prototype.includes habits), or a malformed concatenation that produces an empty argument.","solutions":["Provide exactly one quoted string argument: content.contains(\"meeting\")","Remove any extra arguments; options like case sensitivity are not supported as extra args","Validate the filter string with a CEL parse step before sending it to the API"],"exampleFix":"// before\ncontent.contains()\n\n// after\ncontent.contains(\"meeting\")","handlingStrategy":"validation","validationCode":"// Go: assert the contains/text-match call shape before submitting\nimport (\n  \"fmt\"\n  \"strings\"\n)\nfunc checkTextMatch(field, filter string) error {\n  if !strings.Contains(filter, field+\".contains(\") {\n    return nil\n  }\n  // crude arity check: content between the matching parens must be exactly one quoted literal\n  i := strings.Index(filter, field+\".contains(\") + len(field) + len(\".contains(\")\n  rest := filter[i:]\n  end := strings.Index(rest, \")\")\n  arg := strings.TrimSpace(rest[:end])\n  if arg == \"\" {\n    return fmt.Errorf(\"contains() needs exactly one argument\")\n  }\n  return nil\n}","typeGuard":null,"tryCatchPattern":"err := filterExpr.Validate(parsedAst) // compile the filter first; surface parse errors to the user input form instead of failing the request later","preventionTips":["Run filters through a CEL parse+compile dry-run before saving or executing them","Show users the supported grammar (field.contains(\"literal\")) next to the filter input","Write unit tests for each accepted filter shape your product advertises"],"tags":["cel","filter","parser","validation"],"backgroundTag":null,"analyzedSha":"14d757ce1fb31c78590f374bc042f8dbedbc20d7","analyzedAt":"2026-08-15T09:27:36.538Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}