{"record":{"id":"572b4a23affc82ac","repo":"usememos/memos","slug":"comprehension-range-must-be-a-field-identifier","errorCode":null,"errorMessage":"comprehension range must be a field identifier","messagePattern":"comprehension range must be a field identifier","errorType":"validation","errorClass":null,"httpStatus":400,"severity":"error","filePath":"internal/filter/parser.go","lineNumber":814,"sourceCode":"\t\t\tseen[v] = true\n\t\t\tout = append(out, v)\n\t\t}\n\t}\n\treturn out\n}\n\n// buildComprehensionCondition handles CEL comprehension expressions (exists, all, etc.).\nfunc buildComprehensionCondition(comp *exprv1.Expr_Comprehension, schema Schema) (Condition, error) {\n\t// Determine the comprehension kind by examining the loop initialization and step\n\tkind, err := detectComprehensionKind(comp)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// Get the field being iterated over\n\titerRangeIdent := comp.IterRange.GetIdentExpr()\n\tif iterRangeIdent == nil {\n\t\treturn nil, errors.New(\"comprehension range must be a field identifier\")\n\t}\n\tfieldName := iterRangeIdent.GetName()\n\n\t// Validate the field\n\tfield, ok := schema.Field(fieldName)\n\tif !ok {\n\t\treturn nil, errors.Errorf(\"unknown field %q in comprehension\", fieldName)\n\t}\n\tif field.Kind != FieldKindJSONList {\n\t\treturn nil, errors.Errorf(\"field %q does not support comprehension (must be a list)\", fieldName)\n\t}\n\n\t// Extract the predicate from the loop step\n\tpredicate, err := extractPredicate(comp, schema)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n","sourceCodeStart":796,"sourceCodeEnd":832,"githubUrl":"https://github.com/usememos/memos/blob/14d757ce1fb31c78590f374bc042f8dbedbc20d7/internal/filter/parser.go#L796-L832","documentation":"buildComprehensionCondition translates CEL comprehensions (exists/all over a list field, e.g. tag.exists(t, t.startsWith(\"w\"))). The iteration range must be a bare schema field identifier; comp.IterRange.GetIdentExpr() returning nil (a call, literal, or select expression as the range) fails here.","triggerScenarios":"Filters like [1,2,3].exists(x, x > 1) or size(tag).exists(t, t == \"work\") — the comprehension iterates over something other than a plain field name.","commonSituations":"Porting generic CEL list idioms that iterate over inline lists or computed ranges; the memos filter dialect only supports iterating a declared JSON-list field such as tag.","solutions":["Iterate a schema list field directly: tag.exists(t, t.startsWith(\"w\"))","Replace inline-list tests with the in operator: x in [\"a\",\"b\"]","Check the schema (FieldKind JSONList) for which fields comprehensions accept"],"exampleFix":"// before\n[\"work\",\"urgent\"].exists(t, t.startsWith(\"w\"))\n\n// after\ntag.exists(t, t.startsWith(\"w\"))","handlingStrategy":"validation","validationCode":"// TS: only allow comprehension ranges that are known list fields\nconst LIST_FIELDS = ['tag' /* per schema */];\nif (!LIST_FIELDS.includes(rangeField)) {\n  throw new Error(`comprehension must iterate a list field (${LIST_FIELDS.join(', ')})`);\n}","typeGuard":"const isListField = (f: string): boolean => LIST_FIELDS.includes(f);","tryCatchPattern":null,"preventionTips":["Iterate only declared JSON-list fields (e.g. tag) in exists/all","Use the in operator for membership tests over inline lists","Keep a schema allow-list of comprehension-capable fields in client code"],"tags":["cel","comprehension","lists","filter"],"backgroundTag":null,"analyzedSha":"14d757ce1fb31c78590f374bc042f8dbedbc20d7","analyzedAt":"2026-08-15T09:27:36.538Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}