usememos/memos · error

expression must be a literal

Error message

expression must be a literal

What it means

A generic guard in the filter renderer (expectLiteral) that rejects any value expression which is not a *LiteralValue node. The SQL rendering path can only bind concrete constant values; references, function calls, or arithmetic cannot be translated to placeholders. Callers that wrap it (tag membership, boolean checks, numeric limits) surface this raw message.

Source

Thrown at internal/filter/render.go:850

func (r *renderer) addBoolArg(value bool) string {
	var v any
	switch r.dialect {
	case DialectSQLite:
		if value {
			v = 1
		} else {
			v = 0
		}
	default:
		v = value
	}
	return r.addArg(v)
}

func expectLiteral(expr ValueExpr) (any, error) {
	lit, ok := expr.(*LiteralValue)
	if !ok {
		return nil, errors.New("expression must be a literal")
	}
	return lit.Value, nil
}

func expectBool(expr ValueExpr) (bool, error) {
	lit, err := expectLiteral(expr)
	if err != nil {
		return false, err
	}
	value, ok := lit.(bool)
	if !ok {
		return false, errors.New("boolean literal required")
	}
	return value, nil
}

func expectNumericLiteral(expr ValueExpr) (int64, error) {
	lit, err := expectLiteral(expr)

View on GitHub (pinned to 14d757ce1f)

Solutions

  1. Replace the right-hand side with a literal constant (string in quotes, number, true/false)
  2. If generating filters in code, interpolate evaluated values as literals, not raw symbols
  3. Check the filter grammar docs for which operators accept literals only

Example fix

// before
engine.CompileToStatement(ctx, "tag in [tag_name]", opts)
// after
engine.CompileToStatement(ctx, "tag in [\"tag_name\"]", opts)
Defensive patterns

Strategy: validation

Validate before calling

// Reject filters whose RHS of ==/in contains a bare identifier (non-literal)
var bareIdentRHS = regexp.MustCompile(`==\s*[A-Za-z_][A-Za-z0-9_]*\s*$`)
func hasBareIdentifierRHS(filter string) bool { return bareIdentRHS.MatchString(filter) }

Try / catch

// Treat compile errors as user input errors (400), not server faults
if _, err := engine.CompileToStatement(ctx, filter, opts); err != nil {
  return status.Errorf(codes.InvalidArgument, "invalid filter: %v", err)
}

Prevention

When it happens

Trigger: Compiling a filter where a position requiring a constant gets a non-literal AST node, e.g. `limit in [row_count]`, `pinned == NOT true`, or any identifier/expression used where expectLiteral/expectBool/expectNumericLiteral is invoked.

Common situations: Hand-written filter strings saved in memo queries or API calls that reference fields or functions on the right-hand side; filters generated programmatically that forget to stringify/quote values before serialization.

Related errors


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