Debugging & Profiler
When the Symfony WebProfilerBundle is installed and enabled (automatically in dev environments), the bundle registers a CwaDataCollector that adds a CWA entry to the toolbar and profiler panel. No configuration is required.
The Toolbar Entry
The CWA icon appears in the toolbar on every request. Click it to open the full panel.
Profiler Panel Data
The panel is split into seven sections:
JWT / Authentication
| Field | What it shows |
|---|---|
| Cookie present | Whether a JWT cookie was read on this request |
| Token refreshed | Whether the bundle issued a new JWT on this request (sliding expiry) |
| Cookie cleared | Whether the JWT cookie was deleted (sign-out or expiry) |
Useful for diagnosing login loops, unexpected sign-outs, or confirming that token refresh is triggering correctly.
Route Resolution
| Field | What it shows |
|---|---|
| Resolved path | The URL path the RouteStateProvider matched — confirms which Route entity was resolved |
| Route IRI | The IRI of the matched Route entity (e.g. /_/routes/018e-...) |
| Page data found | Whether the resolved route pointed at a PageData resource rather than a static Page — the first thing to check when a dynamic page renders empty |
Useful for confirming that a URL resolves to the expected route and page, especially when debugging redirect chains or 404 responses.
Publishable ORM Queries
For each ORM query involving a #[Publishable] resource, the panel records which mode was chosen:
| Mode | Meaning |
|---|---|
draft | Admin user in edit mode — the query returns the draft version |
published_only | Anonymous or non-admin — the query returns only the published version |
Both item (single resource) and collection queries are tracked. Useful for confirming that the correct version is served per request and that the publishable filter is not unexpectedly applying the wrong mode.
PageDataProperty Resolutions
Each dynamic component slot (pageDataProperty position) resolved during normalisation is recorded with its outcome:
| Outcome | Meaning |
|---|---|
| ✓ (no skip reason) | Resolved successfully — the component from the PageData property was used |
no_path | No current route path available on this request |
no_pagedata | The route does not point to a PageData resource |
no_request | No current HTTP request (e.g. console context) |
property_missing | The pageDataProperty name does not exist on the PageData class |
no_component | The PageData property is null — no component assigned |
not_published | The component in the property exists but is an unpublished draft |
not_in_allowed | The component's type is not in the ComponentGroup.allowedComponents list |
Useful for diagnosing blank dynamic slots — the skip reason tells you exactly why a slot rendered nothing.
Write Invalidation Fan-out
After any write operation (POST / PATCH / DELETE), the panel shows:
- Entity counts — how many entities were created, updated, and deleted by
PropagateUpdatesListener - Cache-purged IRIs — the list of IRIs whose HTTP cache entries were purged by
HttpCachePurger
Useful for confirming that a mutation invalidated the expected set of cached resources and for auditing unexpected cache churn.
Mercure Publications
| Field | What it shows |
|---|---|
| Publication count | How many Mercure updates were dispatched on this request |
| Topic list | The full list of topics published — one per updated resource |
Useful for verifying that real-time updates are being dispatched after a PATCH or state change, and for auditing which topics are published to.
error level and the save still returns its normal response. Other open pages miss that update until they next fetch. Monitor your error logs for messages containing could not be published. The log context includes topics, resource and exception. Before api-components-bundle#284, the same failure turned an already-saved write into a 500.A malformed publisher JWT is different: Mercure rejects it before sending anything, and that error still fails the request, so a misconfigured secret shows up straight away.Private Mercure Upgrades
When PublishableAwareHub upgrades a Mercure update to private: true (because the resource is an unpublished draft), the panel records:
- The Mercure topics included in the private update
- The PHP class of the resource being published privately
Useful for confirming that draft updates are kept off the public Mercure channel and only delivered to authenticated subscribers.
Error Status Codes
The bundle maps some of its own exceptions to HTTP statuses through api_platform.exception_to_status. API Platform's default mappings apply alongside the bundle's:
| Exception | Status |
|---|---|
| A Symfony Serializer exception, for example a relation given an IRI that doesn't resolve | 400 |
API Platform's InvalidArgumentException | 400 |
Doctrine's OptimisticLockException | 409 |
Doctrine DBAL's UniqueConstraintViolationException | 422 on API Platform 5 only. API Platform 4.4 has no default for it, so it stays a 500 |
The bundle's own entries include a failed cache purge or flush (HttpCachePurgeFailedException, HttpCacheFlushFailedException), which POST /_/rendered_html/purge and POST /_/http_cache/purge return as 502. A purge that fails after an ordinary write is only logged; see Cache Tags and Purging.
An entry in your own exception_to_status config takes precedence over both.
500. A client that handled them as server errors now gets a 4xx.