usememos/memos · error

InvalidArgument

InvalidArgument

Error message

filter cannot be empty

What it means

validateFilter is used by memo-view APIs (e.g. CreateMemoView) to check a user-supplied CEL filter string before persisting it. An empty string is rejected immediately with InvalidArgument; non-empty strings are compiled with the store dialect to catch syntax errors early. The empty check exists because compiling '' would produce a confusing downstream error.

Source

Thrown at server/router/api/v1/memo_view_service.go:226

	}
	if err := s.authorizeMemoViewAccess(ctx, user); err != nil {
		return nil, err
	}

	found, err := s.Store.RemoveUserMemoView(ctx, user.ID, memoViewID)
	if err != nil {
		return nil, status.Errorf(codes.Internal, "failed to delete memo view: %v", err)
	}
	if !found {
		return nil, status.Errorf(codes.NotFound, "memo view not found")
	}

	return &emptypb.Empty{}, nil
}

func (s *APIV1Service) validateFilter(ctx context.Context, filterStr string) error {
	if filterStr == "" {
		return errors.New("filter cannot be empty")
	}

	engine, err := filter.DefaultEngine()
	if err != nil {
		return err
	}

	if _, err := engine.CompileToStatement(ctx, filterStr, filter.RenderOptions{Dialect: s.filterDialect()}); err != nil {
		return errors.Wrap(err, "failed to compile filter")
	}
	return nil
}

// filterDialect maps the configured database driver onto the filter engine dialect.
func (s *APIV1Service) filterDialect() filter.DialectName {
	switch s.Profile.Driver {
	case "mysql":
		return filter.DialectMySQL

View on GitHub (pinned to 14d757ce1f)

Solutions

  1. Require a non-empty filter in the view form before enabling save.
  2. For a catch-all view, use a trivially true CEL expression appropriate to the schema (e.g. 'true' if supported by the compiler) instead of ''.
  3. Test the filter string compiles before persisting (the endpoint does this for you; fail early client-side for better UX).

Example fix

// before
await viewClient.createMemoView({ view: { filter: filterExpr } }); // filterExpr = ''

// after
if (!filterExpr.trim()) throw new Error('Filter is required');
await viewClient.createMemoView({ view: { filter: filterExpr } });
Defensive patterns

Strategy: validation

Validate before calling

if (!filterStr.trim()) throw new Error('Filter cannot be empty');
// optionally pre-compile client-side with a CEL library for faster feedback

Prevention

When it happens

Trigger: CreateMemoView / UpdateMemoView with filter = '' ; a view-creation form where the filter builder returned an empty string; programmatically creating a 'catch-all' view with no conditions.

Common situations: Filter editor cleared by the user but the request still sent; conditional filter construction (cond ? expr : '') leaking empty strings; clients assuming empty filter means 'match everything'.

Related errors


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