{"record":{"id":"438f69af49f6e782","repo":"usememos/memos","slug":"in-operator-expects-two-arguments","errorCode":null,"errorMessage":"in operator expects two arguments","messagePattern":"in operator expects two arguments","errorType":"validation","errorClass":null,"httpStatus":400,"severity":"error","filePath":"internal/filter/parser.go","lineNumber":264,"sourceCode":"func asFloats(left, right any) (float64, float64, bool) {\n\tl, lok := toFloat(left)\n\tr, rok := toFloat(right)\n\treturn l, r, lok && rok\n}\n\nfunc toFloat(v any) (float64, bool) {\n\tswitch x := v.(type) {\n\tcase int64:\n\t\treturn float64(x), true\n\tcase float64:\n\t\treturn x, true\n\t}\n\treturn 0, false\n}\n\nfunc buildInCondition(call *exprv1.Expr_Call, pc parseContext) (Condition, error) {\n\tif len(call.Args) != 2 {\n\t\treturn nil, errors.New(\"in operator expects two arguments\")\n\t}\n\n\t// Handle identifier in list syntax.\n\tif identName, err := getIdentName(call.Args[0]); err == nil {\n\t\tif field, ok := pc.schema.Field(identName); ok && field.Kind == FieldKindVirtualAlias {\n\t\t\tif _, aliasOk := pc.schema.ResolveAlias(identName); !aliasOk {\n\t\t\t\treturn nil, errors.Errorf(\"invalid alias %q\", identName)\n\t\t\t}\n\t\t} else if !ok {\n\t\t\treturn nil, errors.Errorf(\"unknown identifier %q\", identName)\n\t\t}\n\n\t\tif listExpr := call.Args[1].GetListExpr(); listExpr != nil {\n\t\t\tvalues := make([]ValueExpr, 0, len(listExpr.Elements))\n\t\t\tfor _, element := range listExpr.Elements {\n\t\t\t\tvalue, err := buildValueExpr(element, pc)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn nil, err","sourceCodeStart":246,"sourceCodeEnd":282,"githubUrl":"https://github.com/usememos/memos/blob/14d757ce1fb31c78590f374bc042f8dbedbc20d7/internal/filter/parser.go#L246-L282","documentation":"Returned by buildInCondition (internal/filter/parser.go) when an \"@in\" operator call does not have exactly 2 arguments (element, list). CEL's 'in' is always binary, so like the other arity guards this protects against malformed or programmatically built ASTs.","triggerScenarios":"An Expr_Call for @in with arity != 2 — from custom AST construction or macro expansion, not from ordinary filters like tag in [\"a\",\"b\"].","commonSituations":"Programmatic filter generation; synthetic parser tests.","solutions":["Use the standard form: <value> in <list>.","When emitting ASTs, construct @in calls with exactly two arguments.","Report as an engine bug if a plain filter triggers it."],"exampleFix":"# before (AST misuse)\n\n# after\ntag in [\"work\", \"idea\"]","handlingStrategy":"validation","validationCode":"// Go — generate @in as exactly (element, list)\nfunc inList(elem, list string) string { return fmt.Sprintf(\"%s in %s\", elem, list) }","typeGuard":null,"tryCatchPattern":"if err != nil && strings.Contains(err.Error(), \"in operator expects two arguments\") {\n  return errors.Wrap(err, \"internal filter AST inconsistency; report with the filter text\")\n}","preventionTips":["Use '<value> in <list>' text form; never build @in ASTs with extra args.","Validate list literals are well-formed before embedding them.","Round-trip generated in-filters through Compile in tests."],"tags":["cel","filter","parser","in-operator","go"],"backgroundTag":null,"analyzedSha":"14d757ce1fb31c78590f374bc042f8dbedbc20d7","analyzedAt":"2026-08-15T09:27:36.538Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}