{"record":{"id":"4d053de82b24f988","repo":"usememos/memos","slug":"text-match-requires-a-target","errorCode":null,"errorMessage":"text match requires a target","messagePattern":"text match requires a target","errorType":"validation","errorClass":null,"httpStatus":400,"severity":"error","filePath":"internal/filter/parser.go","lineNumber":313,"sourceCode":"\t\tif _, ok := pc.schema.Field(identName); !ok {\n\t\t\treturn nil, errors.Errorf(\"unknown identifier %q\", identName)\n\t\t}\n\t\telement, err := buildValueExpr(call.Args[0], pc)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\treturn &ElementInCondition{\n\t\t\tElement: element,\n\t\t\tField:   identName,\n\t\t}, nil\n\t}\n\n\treturn nil, errors.New(\"invalid use of in operator\")\n}\n\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 {","sourceCodeStart":295,"sourceCodeEnd":331,"githubUrl":"https://github.com/usememos/memos/blob/14d757ce1fb31c78590f374bc042f8dbedbc20d7/internal/filter/parser.go#L295-L331","documentation":"Returned by buildTextMatchCondition (internal/filter/parser.go) for contains (and other text-match functions) when call.Target is nil — i.e., the function was invoked as a plain call, not as a receiver-style method call. Text matching is only supported in member syntax (field.contains(\"x\")), where the receiver becomes the target field.","triggerScenarios":"Writing contains(content, \"x\") instead of content.contains(\"x\"); any filter invoking the text-match function without a member target so the parser has no field to bind the match to.","commonSituations":"Users familiar with function-call syntax migrating from other query languages; generated filters calling contains as a global function.","solutions":["Use receiver syntax: content.contains(\"hello\").","Confirm the field supports text matching (SupportsContains) — e.g., content-like fields, not enums.","When generating filters, emit member-call syntax for contains."],"exampleFix":"# before\ncontains(content, \"hello\")\n\n# after\ncontent.contains(\"hello\")","handlingStrategy":"validation","validationCode":"// Go/TS — lint saved filters for function-style text matching before compile\nvar badContains = regexp.MustCompile(`(?m)(^|[^.\\w])contains\\s*\\(`)\nif badContains.MatchString(filter) {\n  return errors.New(\"use member syntax: field.contains(\\\"value\\\")\")\n}\n_, err := engine.Compile(ctx, filter)","typeGuard":null,"tryCatchPattern":"if err != nil && strings.Contains(err.Error(), \"text match requires a target\") {\n  return status.Errorf(codes.InvalidArgument, \"write text matching as field.contains(\\\"value\\\")\")\n}","preventionTips":["Teach receiver syntax in filter docs/examples: content.contains(\"x\").","Offer filter templates with correct member-call syntax in the UI.","Validate at save time and show the engine's message next to the editor."],"tags":["cel","filter","parser","text-match","contains","go"],"backgroundTag":null,"analyzedSha":"14d757ce1fb31c78590f374bc042f8dbedbc20d7","analyzedAt":"2026-08-15T09:27:36.538Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}