{"record":{"id":"2aff3771e772178f","repo":"usememos/memos","slug":"comprehension-predicate-must-be-a-function-call","errorCode":null,"errorMessage":"comprehension predicate must be a function call","messagePattern":"comprehension predicate must be a function call","errorType":"validation","errorClass":null,"httpStatus":400,"severity":"error","filePath":"internal/filter/parser.go","lineNumber":900,"sourceCode":"\t}\n\n\t// exists/all: accu || predicate  /  accu && predicate  -> predicate is arg[1].\n\t// exists_one: predicate ? accu + 1 : accu               -> predicate is arg[0].\n\tvar predicateExpr *exprv1.Expr\n\tif step.Function == \"_?_:_\" {\n\t\tif len(step.Args) != 3 {\n\t\t\treturn nil, errors.New(\"exists_one loop step must have three arguments\")\n\t\t}\n\t\tpredicateExpr = step.Args[0]\n\t} else {\n\t\tif len(step.Args) != 2 {\n\t\t\treturn nil, errors.New(\"comprehension loop step must have two arguments\")\n\t\t}\n\t\tpredicateExpr = step.Args[1]\n\t}\n\tpredicateCall := predicateExpr.GetCallExpr()\n\tif predicateCall == nil {\n\t\treturn nil, errors.New(\"comprehension predicate must be a function call\")\n\t}\n\n\t// Handle different predicate functions\n\tswitch predicateCall.Function {\n\tcase \"_==_\":\n\t\treturn buildEqualsPredicate(predicateCall, comp.IterVar)\n\tcase \"startsWith\":\n\t\treturn buildStartsWithPredicate(predicateCall, comp.IterVar)\n\tcase \"endsWith\":\n\t\treturn buildEndsWithPredicate(predicateCall, comp.IterVar)\n\tcase \"contains\":\n\t\treturn buildContainsPredicate(predicateCall, comp.IterVar)\n\tdefault:\n\t\treturn nil, errors.Errorf(`unsupported predicate function %q in comprehension (supported: ==, startsWith, endsWith, contains)`, predicateCall.Function)\n\t}\n}\n\n// buildEqualsPredicate extracts the value from t == \"value\".","sourceCodeStart":882,"sourceCodeEnd":918,"githubUrl":"https://github.com/usememos/memos/blob/14d757ce1fb31c78590f374bc042f8dbedbc20d7/internal/filter/parser.go#L882-L918","documentation":"After extracting the predicate node from the loop step, the parser requires it to be a function call (==, startsWith, endsWith, contains). A predicate that is a bare identifier, constant, select expression, or other node type cannot be translated to a SQL predicate and triggers this error.","triggerScenarios":"tag.exists(t, t) (bare iteration variable), tag.all(t, someFlag) where someFlag is an ident, or any predicate not built from one of the four supported operators.","commonSituations":"Users write tag.exists(t, t) expecting truthiness filtering, or reference a boolean property of the iterated element instead of comparing it to a constant.","solutions":["Write the predicate as an explicit call on the iteration variable, e.g. tag.exists(t, t == \"work\") or tag.exists(t, t.contains(\"work\"))","Do not use bare identifiers as predicates; always compare against a string constant"],"exampleFix":"// before\n`tag.exists(t, t)`\n\n// after\n`tag.exists(t, t == \"work\")`","handlingStrategy":"validation","validationCode":"// Require every comprehension predicate to call ==, startsWith, endsWith, or contains\nvar predFn = regexp.MustCompile(`\\.\\s*(exists|all|exists_one)\\s*\\(\\s*\\w+\\s*,\\s*([^)]+)\\)`)\n\nfunc validatePredicates(expr string) error {\n    for _, m := range predFn.FindAllStringSubmatch(expr, -1) {\n        p := m[2]\n        ok := strings.Contains(p, \"==\") || strings.Contains(p, \"startsWith\") ||\n            strings.Contains(p, \"endsWith\") || strings.Contains(p, \"contains\")\n        if !ok {\n            return fmt.Errorf(\"predicate %q must use ==, startsWith, endsWith, or contains\", p)\n        }\n    }\n    return nil\n}","typeGuard":null,"tryCatchPattern":"if err := r.Render(cond); err != nil {\n    if strings.Contains(err.Error(), \"predicate must be a function call\") {\n        return userErr(\"write the tag predicate as t == \\\"value\\\" or t.contains(\\\"value\\\")\")\n    }\n    return err\n}","preventionTips":["Never use a bare identifier as a comprehension predicate","Always compare the iteration variable to a string constant"],"tags":["cel","filter","parser","comprehension","predicate"],"backgroundTag":null,"analyzedSha":"14d757ce1fb31c78590f374bc042f8dbedbc20d7","analyzedAt":"2026-08-15T09:27:36.538Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}