Files
Livio SpringandClaude Opus 5.5 ad835efbc3 fix(api): restore query limits on v1 list endpoints (#12876)
> Stacked on zitadel/zitadel#12875 (reuses `SystemDefaults.QueryLimit`).
Retarget to `main` once that's merged.

## Which Problems Are Solved

The v1 list endpoints (admin, auth, management, system) apply no limit.
A request without `limit` returns all matching rows, and an explicit
`limit` is never capped. The same applies to the 6 change endpoints
(`ListOrgChanges`, `ListUserChanges`, `ListProjectChanges`,
`ListProjectGrantChanges`, `ListAppChanges`, `ListMyUserChanges`).
Without a limit, they return the full history of the object. The only
bound is the audit log retention, which restricts events by age (not by
count) and is disabled by default (`AuditLogRetention: 0s`).

This is a regression. The v1 endpoints previously applied
`Auth/Admin/Mgmt.SearchLimit` (1000) through `EnsureLimit`: a missing
limit defaulted to 1000, and a higher limit was rejected. The check
lived in the old eventsourcing repositories and was dropped when the
endpoints were migrated to the `query` package:
#2342, #2433, #2383, #2612, #2820, #2818, #2838, #3075, #3096.
The `ListQuery.limit` docs still describe the old behavior.

## How the Problems Are Solved

- New `SystemDefaults.V1QueryLimit`: uses `MaxQueryLimit` (1000 by
default) as both the default and the maximum, restoring the previous v1
behavior. Limits above it return `InvalidArgument` (`QUERY-4M0fs`).
- `object.ListQueryToModel` now takes the `SystemDefaults` and applies
it. All 43 v1 call sites were updated.
- The change endpoints apply the same check through
`change.ChangeQueryToModel` (their `ChangeQuery.limit` docs promise the
same default and maximum). Console always passes 30 / 20 there.
- `SystemDefaults` is passed to the admin and system servers. Management
and auth already had them.
- Removed the `Auth.SearchLimit` and `Admin.SearchLimit` configs:
  - `Admin.SearchLimit` was never read.
- `Auth.SearchLimit` only capped the refresh tokens of
`ListMyRefreshTokens` and `RevokeAllMyRefreshTokens` (which revokes the
listed tokens). Both now use `MaxQueryLimit` instead, with the same
default of 1000. This only concerns the legacy refresh tokens, which
haven't been issued since v2.53.
- Unknown config keys are ignored, so existing configs and env vars keep
working.
- Removed the unused `EnsureLimit` methods.
- The v1 list converters take the context first, followed by the system
defaults.
- Updated the `ListQuery.limit` and `ChangeQuery.limit` API docs and the
`MaxQueryLimit` comment in `defaults.yaml`, which now describes where it
applies (v1 lists and change histories, refresh tokens) and that the
events API (`ListEvents`) keeps its own cap of 1000.

## ⚠️ Behavior change

- Requests without `limit` return at most `MaxQueryLimit` (1000)
results.
- Requests with `limit` > 1000 fail with `InvalidArgument`.
- Self-hosters can restore the previous behavior with `MaxQueryLimit:
0`. This applies globally, including to v2.

Console: all v1 list calls pass page sizes ≤ 250, except two that load
all projects of an organization:
- the startup project preload (`listProjects(0, 0)` /
`listGrantedProjects(0, 0)`), used for the project counts, shortcuts and
breadcrumbs. zitadel/zitadel#12881 replaces it (counts from
`details.totalResult`, projects loaded by ID).
- the projects grid view (`project-grid.component.ts`), which has no
pagination. With the default of 1000, it only misses projects (and
pinned grid entries) for organizations with more than 1000 owned or
granted projects. The largest organizations on ZITADEL Cloud are well
below 1000 projects.

## Additional Changes

- Deprecated the unused `query` and `result` fields of
`ListProjectGrantMemberRolesRequest`. The endpoint has no list
semantics: it always returns all roles possible on the project grant
level, like the other member role endpoints, whose requests are empty.

## Additional Context

- Tests:
  - unit tests for `V1QueryLimit` and `ListQueryToModel`
- limit-exceeded integration tests for admin `ListOrgs`, management
`ListUsers`, `ListProjects` and `ListOrgChanges`, and system
`ListInstances`
- A technical advisory covering both PRs is planned.
- Needs a v4.x backport together with zitadel/zitadel#12875.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 08:01:54 +02:00
..
2026-02-04 11:51:43 +01:00
2026-09-04 06:13:37 +02:00
2026-02-04 11:51:43 +01:00