{"record":{"id":"73de4577f016d7d3","repo":"usememos/memos","slug":"set-operations-require-string-elements","errorCode":null,"errorMessage":"set operations require string elements","messagePattern":"set operations require string elements","errorType":"validation","errorClass":null,"httpStatus":400,"severity":"error","filePath":"internal/filter/parser.go","lineNumber":736,"sourceCode":"\t\treturn nil, errors.Errorf(\"unknown identifier %q\", fieldName)\n\t}\n\tif field.Kind != FieldKindJSONList {\n\t\treturn nil, errors.Errorf(\"set operations require a list field, got %q\", fieldName)\n\t}\n\n\tlistExpr := call.Args[1].GetListExpr()\n\tif listExpr == nil {\n\t\treturn nil, errors.New(\"set operations require a list literal as the second argument\")\n\t}\n\tvalues := make([]string, 0, len(listExpr.Elements))\n\tfor _, el := range listExpr.Elements {\n\t\tv, err := getConstValue(el)\n\t\tif err != nil {\n\t\t\treturn nil, errors.Wrap(err, \"set operations only support literal string elements\")\n\t\t}\n\t\ts, ok := v.(string)\n\t\tif !ok {\n\t\t\treturn nil, errors.New(\"set operations require string elements\")\n\t\t}\n\t\tvalues = append(values, s)\n\t}\n\n\tmembership := func(s string) Condition {\n\t\treturn &ElementInCondition{Element: &LiteralValue{Value: s}, Field: fieldName}\n\t}\n\tsizeEquals := func(n int) Condition {\n\t\treturn &ComparisonCondition{\n\t\t\tLeft:     &FunctionValue{Name: \"size\", Args: []ValueExpr{&FieldRef{Name: fieldName}}},\n\t\t\tOperator: CompareEq,\n\t\t\tRight:    &LiteralValue{Value: int64(n)},\n\t\t}\n\t}\n\n\tswitch call.Function {\n\tcase \"sets.contains\":\n\t\tif len(values) == 0 {","sourceCodeStart":718,"sourceCodeEnd":754,"githubUrl":"https://github.com/usememos/memos/blob/14d757ce1fb31c78590f374bc042f8dbedbc20d7/internal/filter/parser.go#L718-L754","documentation":"When compiling a set operation, every element of the list literal must be a string constant. The loop calls getConstValue on each element and type-asserts string; an int, bool, or non-literal element inside the list fails with this error.","triggerScenarios":"Filters like tag in [\"work\", 42] or tag in [\"work\", pinned] — one list element is not a quoted string literal.","commonSituations":"Generating list elements from mixed-typed user input without quoting; copying visibility-style enums as numbers into a string-typed list field filter.","solutions":["Quote every element: tag in [\"work\", \"urgent\"]","JSON-encode each element when building the list from code so quoting/escaping is automatic","Filter numeric enum fields with == instead of a string list"],"exampleFix":"// before\ntag in [\"work\", 42]\n\n// after\ntag in [\"work\", \"42\"]","handlingStrategy":"type-guard","validationCode":"// TS: coerce and verify every element is a string before emitting the list\nconst list = raw.map(String);\nif (!list.every(s => typeof s === 'string')) throw new TypeError('all elements must be strings');","typeGuard":"const isStringListLiteral = (arr: unknown[]): boolean => arr.every(x => typeof x === 'string');","tryCatchPattern":null,"preventionTips":["Map mixed input to strings (String(v)) before building the list literal","Quote each element via JSON.stringify","Keep enum/numeric field filters on == rather than string lists"],"tags":["cel","set-operations","type-mismatch","filter"],"backgroundTag":null,"analyzedSha":"14d757ce1fb31c78590f374bc042f8dbedbc20d7","analyzedAt":"2026-08-15T09:27:36.538Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}