usememos/memos · error
filter must evaluate to a boolean value
Error message
filter must evaluate to a boolean value
What it means
Returned by buildCondition (internal/filter/parser.go) when the AST root (or nested position reached via buildCondition) is a constant expression that is not a boolean — e.g., the whole filter is a string or number literal. The compiled program must be a boolean condition tree; non-boolean constants cannot serve as one.
Source
Thrown at internal/filter/parser.go:30
// single filter observes a single instant.
type parseContext struct {
schema Schema
now time.Time
}
func buildCondition(expr *exprv1.Expr, pc parseContext) (Condition, error) {
switch v := expr.ExprKind.(type) {
case *exprv1.Expr_CallExpr:
return buildCallCondition(v.CallExpr, pc)
case *exprv1.Expr_ConstExpr:
val, err := getConstValue(expr)
if err != nil {
return nil, err
}
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) {View on GitHub (pinned to 14d757ce1f)
Solutions
- Make the filter a full boolean expression: compare a field to the value (content.contains(\"hello\")", "pinned == true").
- If generating filters in code, template 'field op value', never inject the raw value alone.
- Validate with a small CEL type-check pass or example filters before saving a user-defined filter.
Example fix
# before
"hello"
# after
content.contains("hello") Defensive patterns
Strategy: validation
Validate before calling
// Go — smoke-compile saved filters before persisting them
if _, err := engine.Compile(ctx, candidate); err != nil {
return errors.Wrap(err, "invalid filter")
} Try / catch
if err != nil {
if strings.Contains(err.Error(), "must evaluate to a boolean") {
return status.Errorf(codes.InvalidArgument, "filter must be a boolean expression, e.g. pinned == true")
}
return err
} Prevention
- Document example boolean filters next to the input field.
- Validate filters with Compile at save time, not at query time.
- When templating filters, always emit 'field <op> value', never a bare value.
When it happens
Trigger: A filter like "\"hello\"" or "42" or "1.5" — CEL compiles these fine (they are valid expressions of non-bool type), but buildCondition's ConstExpr branch only accepts bool constants and returns ConstantCondition; anything else hits this error. Note CEL normally type-checks top-level bool, so this often surfaces via sub-expressions in untyped code paths.
Common situations: Users pasting a bare value instead of a comparison; quoting the entire expression; building filters programmatically and interpolating a value where a predicate was expected.
Related errors
- invalid use of in operator
- filter expression is empty
- unsupported top-level expression
- logical AND expects two arguments
- logical OR expects two arguments
AI-assisted analysis of usememos/memos@14d757ce1f (2026-08-15).
Data as JSON: /api/errors/3bee948ddff25d61.
Report an issue: GitHub.