usememos/memos · error
unsupported top-level expression
Error message
unsupported top-level expression
What it means
Returned by buildCondition's default branch when the top-level (or nested) AST node kind is a CallExpr, ConstExpr, IdentExpr, or Comprehension that was not matched — practically, an expression shape the condition builder does not translate. It marks the boundary of the supported CEL subset (logic ops, comparisons, in, text matches, comprehensions, boolean idents/constants).
Source
Thrown at internal/filter/parser.go:44
}
if v, ok := val.(bool); ok {
return &ConstantCondition{Value: v}, nil
}
return nil, errors.New("filter must evaluate to a boolean value")
case *exprv1.Expr_IdentExpr:
name := v.IdentExpr.GetName()
field, ok := pc.schema.Field(name)
if !ok {
return nil, errors.Errorf("unknown identifier %q", name)
}
if field.Type != FieldTypeBool {
return nil, errors.Errorf("identifier %q is not boolean", name)
}
return &FieldPredicateCondition{Field: name}, nil
case *exprv1.Expr_ComprehensionExpr:
return buildComprehensionCondition(v.ComprehensionExpr, pc.schema)
default:
return nil, errors.New("unsupported top-level expression")
}
}
func buildCallCondition(call *exprv1.Expr_Call, pc parseContext) (Condition, error) {
switch call.Function {
case "_&&_":
if len(call.Args) != 2 {
return nil, errors.New("logical AND expects two arguments")
}
left, err := buildCondition(call.Args[0], pc)
if err != nil {
return nil, err
}
right, err := buildCondition(call.Args[1], pc)
if err != nil {
return nil, err
}
return &LogicalCondition{View on GitHub (pinned to 14d757ce1f)
Solutions
- Rewrite the filter using supported constructs: field comparisons, &&/||/!, in, contains, and macro comprehensions.
- Check the documented filter grammar/schema for the resource you are filtering.
- Simplify to nested boolean comparisons of the same intent.
Example fix
# before (unsupported shape) [tag in ["a","b"] ? true : false] # after tag in ["a", "b"]
Defensive patterns
Strategy: validation
Validate before calling
// Go — restrict input to the supported grammar before compiling
var allowed = regexp.MustCompile(`^[a-zA-Z0-9_.()\s\[\]",!=<>@&|!'-]+$`)
if !allowed.MatchString(filter) {
return errors.New("filter uses unsupported syntax")
}
_, err := engine.Compile(ctx, filter) Try / catch
if err != nil && strings.Contains(err.Error(), "unsupported top-level expression") {
return status.Errorf(codes.InvalidArgument, "unsupported filter syntax; use comparisons, in, contains, and logical operators")
} Prevention
- Keep filters within the documented subset: comparisons, in, contains, &&/||/!, macros.
- Provide an interactive filter tester in the UI with the engine's real errors.
- Avoid pasting raw CEL from other systems without adapting to this schema.
When it happens
Trigger: A filter whose root is a list/map literal, a ternary result of non-supported form, or any macro/expression kind outside the handled ExprKind cases. CEL's env may accept it syntactically while the Memos condition builder refuses to compile it to a Condition.
Common situations: Power users writing CEL beyond the supported subset (list literals, index expressions); filters written against a different CEL schema; engine version gaps after new syntax was allowed by env.Compile but not yet mapped in the parser.
Related errors
- filter must evaluate to a boolean value
- logical AND expects two arguments
- logical OR expects two arguments
- logical NOT expects one argument
- comparison expects two arguments
AI-assisted analysis of usememos/memos@14d757ce1f (2026-08-15).
Data as JSON: /api/errors/9fbe6f8acb43076b.
Report an issue: GitHub.