usememos/memos · error
expression is not an identifier
Error message
expression is not an identifier
What it means
getIdentName extracts the field name from an expression and only succeeds when the expression is an identifier (exprv1.Expr_IdentExpr). Callers use it for receivers of contains/matches, targets of set operations, and comprehension ranges; when the sub-expression is a call, literal, or select, this error surfaces.
Source
Thrown at internal/filter/parser.go:462
return CompareNeq, nil
case "_<_":
return CompareLt, nil
case "_>_":
return CompareGt, nil
case "_<=_":
return CompareLte, nil
case "_>=_":
return CompareGte, nil
default:
return "", errors.Errorf("unsupported comparison operator %q", fn)
}
}
func getIdentName(expr *exprv1.Expr) (string, error) {
if ident := expr.GetIdentExpr(); ident != nil {
return ident.GetName(), nil
}
return "", errors.New("expression is not an identifier")
}
func getConstValue(expr *exprv1.Expr) (interface{}, error) {
v, ok := expr.ExprKind.(*exprv1.Expr_ConstExpr)
if !ok {
return nil, errors.New("expression is not a literal")
}
switch x := v.ConstExpr.ConstantKind.(type) {
case *exprv1.Constant_StringValue:
return v.ConstExpr.GetStringValue(), nil
case *exprv1.Constant_Int64Value:
return v.ConstExpr.GetInt64Value(), nil
case *exprv1.Constant_Uint64Value:
return int64(v.ConstExpr.GetUint64Value()), nil
case *exprv1.Constant_DoubleValue:
return v.ConstExpr.GetDoubleValue(), nil
case *exprv1.Constant_BoolValue:
return v.ConstExpr.GetBoolValue(), nilView on GitHub (pinned to 14d757ce1f)
Solutions
- Put a bare schema field where a field is expected: content.contains("x")
- Apply size() inside comparisons only: size(tag) > 1, never as a text-match receiver
- Simplify the left side to a single identifier before the dot
Example fix
// before
content.size().contains("x")
// after
content.contains("x") Defensive patterns
Strategy: validation
Validate before calling
// Go (AST level): assert the receiver is an identifier
if call.GetTarget().GetIdentExpr() == nil {
return errors.New("receiver must be a bare field name")
} Type guard
func isIdent(e *exprv1.Expr) bool { return e.GetIdentExpr() != nil } Prevention
- Write a bare field before the dot in contains/matches calls
- Never chain method calls in the filter DSL
- If you build ASTs, validate receivers are identifiers before compiling
When it happens
Trigger: Filters where a field position holds a non-identifier: content.size().contains("x") (method chained on a call), 5.contains("x"), or (a || b).matches("x").
Common situations: Chaining calls so the receiver is itself a call result; wrapping field names in parentheses or expressions; typos that turn an identifier into a function call.
Related errors
- filter must evaluate to a boolean value
- unsupported top-level expression
- logical AND expects two arguments
- logical OR expects two arguments
- logical NOT expects one argument
AI-assisted analysis of usememos/memos@14d757ce1f (2026-08-15).
Data as JSON: /api/errors/232d3a4bc77f621f.
Report an issue: GitHub.