usememos/memos · error

filter expression is empty

Error message

filter expression is empty

What it means

Returned by Engine.Compile (internal/filter/engine.go) when the CEL filter string is empty or whitespace-only after TrimSpace. An empty filter has no condition tree to execute, so compilation is rejected up front rather than producing a nil program.

Source

Thrown at internal/filter/engine.go:50

		nowFunc: time.Now,
	}, nil
}

// Program stores a compiled filter condition.
type Program struct {
	schema    Schema
	condition Condition
}

// ConditionTree exposes the underlying condition tree.
func (p *Program) ConditionTree() Condition {
	return p.condition
}

// Compile parses the filter string into an executable program.
func (e *Engine) Compile(_ context.Context, filter string) (*Program, error) {
	if strings.TrimSpace(filter) == "" {
		return nil, errors.New("filter expression is empty")
	}

	ast, issues := e.env.Compile(filter)
	if issues != nil && issues.Err() != nil {
		return nil, errors.Wrap(issues.Err(), "failed to compile filter")
	}
	parsed, err := cel.AstToParsedExpr(ast)
	if err != nil {
		return nil, errors.Wrap(err, "failed to convert AST")
	}

	cond, err := buildCondition(parsed.GetExpr(), parseContext{schema: e.schema, now: e.nowFunc()})
	if err != nil {
		return nil, err
	}

	return &Program{
		schema:    e.schema,

View on GitHub (pinned to 14d757ce1f)

Solutions

  1. Omit the filter field entirely (proto optional/empty string means 'no filter') when you want all results.
  2. Trim input upstream and treat empty as 'match everything' instead of compiling it.
  3. Provide at least one boolean expression, e.g., "pinned == true".

Example fix

// before
prog, err := engine.Compile(ctx, strings.TrimSpace(filter)) // "" -> error

// after
if strings.TrimSpace(filter) == "" {
  return listAll(ctx) // no filter means match everything
}
prog, err := engine.Compile(ctx, filter)
Defensive patterns

Strategy: validation

Validate before calling

// Go — treat empty as 'no filter' before compiling
trimmed := strings.TrimSpace(filter)
if trimmed == "" {
  return engine.ListAll(ctx) // or return an empty Program that matches everything
}
prog, err := engine.Compile(ctx, trimmed)

Try / catch

prog, err := engine.Compile(ctx, filter)
if err != nil {
  if strings.Contains(err.Error(), "filter expression is empty") {
    return status.Errorf(codes.InvalidArgument, "filter must not be empty; omit the field to list all")
  }
  return err
}

Prevention

When it happens

Trigger: Calling Engine.Compile with "", " ", or a value that trims to empty — e.g., a ListMemos request with filter unset-but-empty-string, a UI saved-search whose filter was cleared, or trimming user input before compile.

Common situations: Frontend sending filter: "" instead of omitting the field; saved views with cleared filters; scripts copying an example but leaving the filter blank.

Related errors


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