{"record":{"id":"26dbd23de5bc1cc4","repo":"usememos/memos","slug":"startswith-expects-exactly-one-argument","errorCode":null,"errorMessage":"startsWith expects exactly one argument","messagePattern":"startsWith expects exactly one argument","errorType":"validation","errorClass":null,"httpStatus":400,"severity":"error","filePath":"internal/filter/parser.go","lineNumber":960,"sourceCode":"\t}\n\n\treturn &EqualsPredicate{Value: valueStr}, nil\n}\n\nfunc isIterVarExpr(expr *exprv1.Expr, iterVar string) bool {\n\ttarget := expr.GetIdentExpr()\n\treturn target != nil && target.GetName() == iterVar\n}\n\n// buildStartsWithPredicate extracts the pattern from t.startsWith(\"prefix\").\nfunc buildStartsWithPredicate(call *exprv1.Expr_Call, iterVar string) (PredicateExpr, error) {\n\t// Verify the target is the iteration variable\n\tif target := call.Target.GetIdentExpr(); target == nil || target.GetName() != iterVar {\n\t\treturn nil, errors.Errorf(\"startsWith target must be the iteration variable %q\", iterVar)\n\t}\n\n\tif len(call.Args) != 1 {\n\t\treturn nil, errors.New(\"startsWith expects exactly one argument\")\n\t}\n\n\tprefix, err := getConstValue(call.Args[0])\n\tif err != nil {\n\t\treturn nil, errors.Wrap(err, \"startsWith argument must be a constant string\")\n\t}\n\n\tprefixStr, ok := prefix.(string)\n\tif !ok {\n\t\treturn nil, errors.New(\"startsWith argument must be a string\")\n\t}\n\n\treturn &StartsWithPredicate{Prefix: prefixStr}, nil\n}\n\n// buildEndsWithPredicate extracts the pattern from t.endsWith(\"suffix\").\nfunc buildEndsWithPredicate(call *exprv1.Expr_Call, iterVar string) (PredicateExpr, error) {\n\tif target := call.Target.GetIdentExpr(); target == nil || target.GetName() != iterVar {","sourceCodeStart":942,"sourceCodeEnd":978,"githubUrl":"https://github.com/usememos/memos/blob/14d757ce1fb31c78590f374bc042f8dbedbc20d7/internal/filter/parser.go#L942-L978","documentation":"buildStartsWithPredicate translates t.startsWith(\"prefix\"). It validates that the call target is the iteration variable and that exactly one argument is passed. More or fewer than one argument is rejected.","triggerScenarios":"Programmatically constructed startsWith call with wrong arity; textual CEL always emits one arg, so this is a guard against malformed ASTs.","commonSituations":"AST-building tests or custom CEL environments emitting startsWith with 0 or 2 args.","solutions":["Use the textual form tag.exists(t, t.startsWith(\"work\"))","Emit exactly one constant string argument when building the call AST"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"if err := r.Render(cond); err != nil {\n    if strings.Contains(err.Error(), \"startsWith expects exactly one argument\") {\n        return errors.New(\"call startsWith with a single quoted prefix\")\n    }\n    return err\n}","preventionTips":["Pass exactly one string argument to startsWith","Use textual method-call syntax t.startsWith(\"...\")"],"tags":["cel","filter","parser","comprehension","string-ops"],"backgroundTag":null,"analyzedSha":"14d757ce1fb31c78590f374bc042f8dbedbc20d7","analyzedAt":"2026-08-15T09:27:36.538Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}