usememos/memos · error

InvalidArgument

InvalidArgument

Error message

empty expression

What it means

In the ListUsers CEL filter path, the parsed AST's root expression is nil, which happens when the CEL library produced an empty AST from an empty/whitespace filter string. extractUsernameFromAST guards the nil root before inspecting kinds. Returned as InvalidArgument.

Source

Thrown at server/router/api/v1/user_service_filter.go:54

	// Parse and check the filter expression
	celAST, issues := env.Compile(filterStr)
	if issues != nil && issues.Err() != nil {
		return "", errors.Wrapf(issues.Err(), "invalid filter expression: %s", filterStr)
	}

	// Extract username from the AST
	username, err := extractUsernameFromAST(celAST.NativeRep().Expr())
	if err != nil {
		return "", err
	}

	return username, nil
}

// extractUsernameFromAST extracts the username value from a CEL AST expression.
func extractUsernameFromAST(expr ast.Expr) (string, error) {
	if expr == nil {
		return "", errors.New("empty expression")
	}

	// Check if this is a call expression (for ==, !=, etc.)
	if expr.Kind() != ast.CallKind {
		return "", errors.New("filter must be a comparison expression (e.g., username == 'value')")
	}

	call := expr.AsCall()

	// We only support == operator
	if call.FunctionName() != "_==_" {
		return "", errors.Errorf("unsupported operator: %s (only '==' is supported)", call.FunctionName())
	}

	// The call should have exactly 2 arguments
	args := call.Args()
	if len(args) != 2 {
		return "", errors.New("invalid comparison expression")

View on GitHub (pinned to 14d757ce1f)

Solutions

  1. Omit the filter field entirely when no username filtering is wanted.
  2. Client-side guard: if (!filter.trim()) delete request.filter.
  3. If a 'list all' behavior is needed from a variable, branch the call instead of sending an empty filter.

Example fix

// before
const users = await userClient.listUsers({ filter }); // filter = ''

// after
const req = {};
if (filter.trim()) req.filter = filter; // e.g. "username == 'alice'"
const users = await userClient.listUsers(req);
Defensive patterns

Strategy: validation

Validate before calling

if (filter !== undefined && !filter.trim()) {
  throw new Error('filter must be non-empty when provided');
}

Prevention

When it happens

Trigger: ListUsers(filter='') or filter=' '; a client defaulting the filter field to empty string; a filter builder that joins zero conditions into ''.

Common situations: Optional search box on a user list page serializing as empty string instead of being omitted; admin tooling passing an env-provided filter that is unset.

Related errors


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