{"record":{"id":"6235dd3ac5c15522","repo":"usememos/memos","slug":"arithmetic-requires-two-arguments","errorCode":null,"errorMessage":"arithmetic requires two arguments","messagePattern":"arithmetic requires two arguments","errorType":"validation","errorClass":null,"httpStatus":400,"severity":"error","filePath":"internal/filter/parser.go","lineNumber":548,"sourceCode":"\t\tif ident.GetName() == \"now\" {\n\t\t\treturn now.Unix(), true, nil\n\t\t}\n\t\treturn 0, false, nil\n\t}\n\n\tcall := expr.GetCallExpr()\n\tif call == nil {\n\t\treturn 0, false, nil\n\t}\n\n\tswitch call.Function {\n\tcase \"timestamp\":\n\t\treturn evaluateTimestamp(call)\n\tcase \"duration\":\n\t\treturn evaluateDuration(call)\n\tcase \"_+_\", \"_-_\", \"_*_\", \"_/_\", \"_%_\":\n\t\tif len(call.Args) != 2 {\n\t\t\treturn 0, false, errors.New(\"arithmetic requires two arguments\")\n\t\t}\n\t\tleft, ok, err := evaluateNumeric(call.Args[0], now)\n\t\tif err != nil {\n\t\t\treturn 0, false, err\n\t\t}\n\t\tif !ok {\n\t\t\treturn 0, false, nil\n\t\t}\n\t\tright, ok, err := evaluateNumeric(call.Args[1], now)\n\t\tif err != nil {\n\t\t\treturn 0, false, err\n\t\t}\n\t\tif !ok {\n\t\t\treturn 0, false, nil\n\t\t}\n\t\tswitch call.Function {\n\t\tcase \"_+_\":\n\t\t\treturn left + right, true, nil","sourceCodeStart":530,"sourceCodeEnd":566,"githubUrl":"https://github.com/usememos/memos/blob/14d757ce1fb31c78590f374bc042f8dbedbc20d7/internal/filter/parser.go#L530-L566","documentation":"evaluateNumeric constant-folds arithmetic (_+_, _-_, _*_, _/_, _%_) on timestamps, durations, and integers, and requires the binary operator to have exactly two operands. A hand-constructed AST with wrong arity is rejected here; text-parsed filters normally cannot produce this because the CEL grammar fixes binary arity.","triggerScenarios":"Directly building an exprv1.Expr_Call for arithmetic with len(Args) != 2, e.g. an AST optimizer collapsing '_-_' to one operand after removing a foldable term.","commonSituations":"AST manipulation code (partial evaluators, filter rewriters) that mutates Args arrays; integrating third-party CEL tooling that emits non-canonical call nodes.","solutions":["Ensure binary arithmetic calls always carry exactly two args when constructing or rewriting ASTs","Re-serialize the AST to a filter string and re-parse to validate","Add unit tests asserting arity invariants after each rewrite pass"],"exampleFix":"// before (rewrite dropped an operand)\ncall.Args = call.Args[:1]\n\n// after\ncall.Args = []*exprv1.Expr{left, right}","handlingStrategy":"validation","validationCode":"// Go (AST builder/rewriter): enforce binary arity\nswitch fn {\ncase \"_+_\", \"_-_\", \"_*_\", \"_/_%_\":\n    if len(args) != 2 { return errors.New(\"binary op needs two operands\") }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Keep binary arithmetic calls at exactly two args in any AST tooling","Add tests asserting call arity after optimizer passes","Re-parse serialized filters to catch structural corruption"],"tags":["cel","ast","arithmetic","internal"],"backgroundTag":null,"analyzedSha":"14d757ce1fb31c78590f374bc042f8dbedbc20d7","analyzedAt":"2026-08-15T09:27:36.538Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}