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(), nil

View on GitHub (pinned to 14d757ce1f)

Solutions

  1. Put a bare schema field where a field is expected: content.contains("x")
  2. Apply size() inside comparisons only: size(tag) > 1, never as a text-match receiver
  3. 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

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


AI-assisted analysis of usememos/memos@14d757ce1f (2026-08-15). Data as JSON: /api/errors/232d3a4bc77f621f. Report an issue: GitHub.