Skip to content

Debugging and troubleshooting

Edit this page

Inspect the service and configuration

Use the console to inspect the wiring:

1
2
3
$ php bin/console debug:autowiring PaginatorInterface
$ php bin/console debug:config ux_pagination
$ php bin/console debug:twig --filter=ux_pagination

Use the Symfony profiler to inspect the current query parameters, the generated route, the Doctrine queries and the query count.

HTTP and failure policy

The paginator never redirects an invalid or out-of-range request. Symfony converts exceptions implementing HttpExceptionInterface into their HTTP status when they reach the kernel:

Condition Status Behavior
Malformed request page 400 HttpFoundation rejects conversion
Non-positive request page 400 One-based invariant is rejected
Malformed or invalidated cursor 400 InvalidCursorException
Configured maximum offset exceeded 400 OffsetLimitExceededException
Page beyond the final page 200 Empty out-of-range result by default
Page beyond the final page 404 With throwOnOutOfRange()
Full navigation exceeds its limit 500 Developer configuration error

The 404 policy performs an exact count. It is opt-in because lookahead and cursor pagination intentionally avoid totals. For a redirect, a canonical URL or another response, implement that policy in the controller or in an application event listener.

Malformed page

When paginate() receives no explicit page, it delegates HTTP conversion to the current Request parameter bag. HttpFoundation rejects malformed values; UX Pagination then rejects zero and negative integers. Neither the paginator nor a package exception stores the raw input.

Leave the page argument empty in an ordinary controller to use this automatic resolution. When the application passes paginate(page: $page), the value is already typed PHP input and RequestStack is intentionally not consulted.

Unsafe offset

OffsetLimitExceededException protects the source from unexpectedly deep offsets. Check whether a bot or an unbounded UI produced the URL. Raise max_offset only for a measured, indexed use case; otherwise use cursor pagination.

Unsupported Doctrine count

UnsupportedDoctrineQueryException reports GROUP BY, HAVING or multiple roots whose total cannot be inferred safely. Use total(), lookahead() or a custom adapter.

Invalid cursor

InvalidCursorException can indicate a malformed token, a changed application secret, context or order. With the built-in Doctrine adapters, a changed source query or bound source parameter also changes the cursor context. Compare the complete source query and the orderBy() call between requests. For a custom adapter, inspect getCursorContext() and resolveCursorOrder(). Do not log the full token at info level; a digest is sufficient for correlation.

Cursor query already ordered

Doctrine cursor pagination rejects a source QueryBuilder with ORDER BY. Remove it and express the entire deterministic order with cursor()->orderBy().

The links keep real href values, so a missing LiveComponent runtime falls back to an ordinary request by design. When the fallback is not intended, confirm that:

  • LiveComponent is installed;
  • the component root contains {{ attributes }};
  • the component uses ComponentWithPaginationTrait;
  • the renderer receives link_attributes: this.paginationLinkAttributes.

Theme template not found

The theme is passed directly to Twig and must be a complete template name. Use an application path such as pagination/product.html.twig or a namespace such as @UXPagination/theme/bootstrap.html.twig. Place bundle overrides under templates/bundles/UXPaginationBundle/theme/.

For a new application theme, pass an explicit path and keep repeated markup in application-owned includes or partials. The pagination result supplies URLs and state, so these themes do not need to copy PHP logic.

This work, including the code samples, is licensed under a Creative Commons BY-SA 3.0 license.
TOC
    Version