{"record":{"id":"c824933502b7a2b4","repo":"usememos/memos","slug":"comprehension-accumulator-must-be-initialized-with","errorCode":null,"errorMessage":"comprehension accumulator must be initialized with a constant","messagePattern":"comprehension accumulator must be initialized with a constant","errorType":"validation","errorClass":null,"httpStatus":400,"severity":"error","filePath":"internal/filter/parser.go","lineNumber":847,"sourceCode":"\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn &ListComprehensionCondition{\n\t\tKind:      kind,\n\t\tField:     fieldName,\n\t\tIterVar:   comp.IterVar,\n\t\tPredicate: predicate,\n\t}, nil\n}\n\n// detectComprehensionKind determines if this is an exists() macro.\n// Only exists() is currently supported.\nfunc detectComprehensionKind(comp *exprv1.Expr_Comprehension) (ComprehensionKind, error) {\n\t// Check the accumulator initialization\n\taccuInit := comp.AccuInit.GetConstExpr()\n\tif accuInit == nil {\n\t\treturn \"\", errors.New(\"comprehension accumulator must be initialized with a constant\")\n\t}\n\n\t// exists() starts with false and uses OR (||) in loop step\n\tif !accuInit.GetBoolValue() {\n\t\tif step := comp.LoopStep.GetCallExpr(); step != nil && step.Function == \"_||_\" {\n\t\t\treturn ComprehensionExists, nil\n\t\t}\n\t}\n\n\t// all() starts with true and uses AND (&&) in the loop step.\n\tif accuInit.GetBoolValue() {\n\t\tif step := comp.LoopStep.GetCallExpr(); step != nil && step.Function == \"_&&_\" {\n\t\t\treturn ComprehensionAll, nil\n\t\t}\n\t}\n\n\t// exists_one() starts at int(0) and increments via a conditional (predicate ?\n\t// accu + 1 : accu) in the loop step.","sourceCodeStart":829,"sourceCodeEnd":865,"githubUrl":"https://github.com/usememos/memos/blob/14d757ce1fb31c78590f374bc042f8dbedbc20d7/internal/filter/parser.go#L829-L865","documentation":"This error comes from the CEL-to-SQL filter parser in internal/filter. When the parser meets a comprehension (the AST form a CEL macro like exists()/all()/exists_one() expands to), it identifies which macro it is by inspecting the accumulator initialization expression. detectComprehensionKind requires AccuInit to be a constant literal (false for exists, true for all, int 0 for exists_one). If the accumulator is initialized with anything that is not a constant expression, the parser cannot classify the comprehension and refuses it.","triggerScenarios":"A CEL filter expression whose macro accumulator is not a plain constant, e.g. a user-supplied or programmatically built expression like tag.exists(t, t == variableName) where the macro was hand-constructed instead of using the standard exists() syntax, or a modified/custom CEL environment that rewrites the accumulator init to a non-constant expr. Passing an already-macro-expanded AST with AccuInit as a call or ident instead of a const produces this on Parse of the filter.","commonSituations":"Building CEL expressions programmatically with cel.NewAst / custom macros rather than parsing the textual form; upgrading cel-go versions that change macro expansion shape; users pasting exotic filter strings (lambda-style syntax) into the memos filter UI that the CEL parser turns into non-standard comprehensions.","solutions":["Rewrite the filter to use the plain macro form, e.g. tag.exists(t, t == \"work\") with literal false/true accumulator semantics","If you build ASTs programmatically, set the comprehension's AccuInit to a constant expression (bool false for exists, true for all, int64 0 for exists_one)","Check the cel-go version used by the project has not changed macro expansion; pin/align with the version in go.mod"],"exampleFix":"// before (invalid accumulation shape / non-macro comprehension)\nfilter.Parse(`tag.exists(t, t == someVar)`)\n\n// after\nfilter.Parse(`tag.exists(t, t == \"work\")`)","handlingStrategy":"validation","validationCode":"// Reject non-standard comprehensions before rendering: only use textual macros\nimport \"regexp\"\n\nvar comprehensionLike = regexp.MustCompile(`\\.\\s*(map|filter|sum|exists|all|exists_one)\\s*\\(`)\n\nfunc precheckFilter(expr string) error {\n    for _, m := range comprehensionLike.FindAllStringSubmatch(expr, -1) {\n        switch m[1] {\n        case \"exists\", \"all\", \"exists_one\":\n        default:\n            return fmt.Errorf(\"unsupported macro %q\", m[1])\n        }\n    }\n    return nil\n}","typeGuard":null,"tryCatchPattern":"err := renderer.Render(cond)\nif err != nil {\n    if strings.Contains(err.Error(), \"comprehension accumulator\") {\n        // surface as user-facing validation message\n        return fmt.Errorf(\"invalid filter: use exists()/all()/exists_one() macros: %w\", err)\n    }\n    return err\n}","preventionTips":["Always author filters as textual CEL macros, never build comprehension ASTs by hand","Pin the cel-go version to keep macro expansion shapes stable","Validate user filters in the UI before submitting them to the API"],"tags":["cel","filter","parser","comprehension"],"backgroundTag":null,"analyzedSha":"14d757ce1fb31c78590f374bc042f8dbedbc20d7","analyzedAt":"2026-08-15T09:27:36.538Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}