usememos/memos · error
comparison must start with a field reference or supported fu
Error message
comparison must start with a field reference or supported function
What it means
The renderer translates a ComparisonCondition by switching on the left-hand expression type: FieldRef, FunctionValue, or FieldAccessorValue. Anything else — literals, arithmetic results, or custom ValueExpr implementations — cannot start an SQL comparison, so this error is thrown.
Source
Thrown at internal/filter/render.go:181
}
switch field.Kind {
case FieldKindBoolColumn:
return r.renderBoolColumnComparison(field, cond.Operator, cond.Right)
case FieldKindJSONBool:
return r.renderJSONBoolComparison(field, cond.Operator, cond.Right)
case FieldKindJSONExists:
return r.renderJSONExistsComparison(field, cond.Operator, cond.Right)
case FieldKindScalar:
return r.renderScalarComparison(field, cond.Operator, cond.Right)
default:
return renderResult{}, errors.Errorf("field %q does not support comparison", field.Name)
}
case *FunctionValue:
return r.renderFunctionComparison(left, cond.Operator, cond.Right)
case *FieldAccessorValue:
return r.renderAccessorComparison(left, cond.Operator, cond.Right)
default:
return renderResult{}, errors.New("comparison must start with a field reference or supported function")
}
}
// accessorSpec maps a CEL timestamp accessor to per-dialect SQL date-part tokens
// and the offset to subtract so the result matches CEL's base (e.g. CEL months
// are 0-based but every dialect reports 1-based, so off=1). off is indexed
// [sqlite, postgres, mysql].
type accessorSpec struct {
sqlite string // strftime format specifier
pg string // EXTRACT field
mysql string // function name
off [3]int
}
var accessorSpecs = map[string]accessorSpec{
"getFullYear": {"%Y", "YEAR", "YEAR", [3]int{0, 0, 0}},
"getMonth": {"%m", "MONTH", "MONTH", [3]int{1, 1, 1}},
"getDate": {"%d", "DAY", "DAYOFMONTH", [3]int{0, 0, 0}},View on GitHub (pinned to 14d757ce1f)
Solutions
- Put the field or function on the left: content.size() > 42 instead of 42 < content.size()
- If extending the library, add a case for your custom ValueExpr type in renderComparison or convert it to a FieldRef before rendering
- Fold literal-vs-literal comparisons in the parser instead of sending them to the renderer
Example fix
// before `42 < content.size()` // after `content.size() > 42`
Defensive patterns
Strategy: validation
Validate before calling
// In Go, before rendering, verify the comparison left side is a supported type
func isRenderableLeft(v filter.ValueExpr) bool {
switch v.(type) {
case *filter.FieldRef, *filter.FunctionValue, *filter.FieldAccessorValue:
return true
}
return false
}
// ok := isRenderableLeft(cond.Left) Type guard
func isRenderableLeft(v filter.ValueExpr) bool {
switch v.(type) {
case *filter.FieldRef, *filter.FunctionValue, *filter.FieldAccessorValue:
return true
default:
return false
}
} Try / catch
if _, err := r.Render(cond); err != nil {
if strings.Contains(err.Error(), "must start with a field reference") {
return userErr("put the field or function on the left of the comparison")
}
return err
} Prevention
- Write comparisons field-first: content.size() > 42, not 42 < content.size()
- Validate left-hand expression type before constructing ComparisonCondition programmatically
- Extend renderComparison if you introduce new ValueExpr types
When it happens
Trigger: A filter like 42 < content.size or "abc" == tag — starting a comparison with a literal. Also triggered when user code constructs a ComparisonCondition with a custom ValueExpr implementation the renderer does not know.
Common situations: Reversed comparisons written by users; library extensions adding new ValueExpr types without extending renderComparison; programmatic construction of filter conditions.
Related errors
- size() expects one argument
- size() argument must be a field
- IN operator requires a field on the left-hand side
- tags must be compared with string literals
- tag attribute is not configured
AI-assisted analysis of usememos/memos@14d757ce1f (2026-08-15).
Data as JSON: /api/errors/2509c70980942fe1.
Report an issue: GitHub.