Unmatched and unauthenticated web routes return a JSON 404 instead of redirecting to / #135
Labels
No labels
bug
devops
duplicate
enhancement
good first issue
layout
next major release
next minor release
question
research
testing
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference: lvl0/fedi-feed-router#135
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Problem
Loading
http://localhost:8000/dashboardin a browser after the containers come back up shows a "cannot find the page" result instead of a usable page. Navigating to the app root produces the login screen, after which/dashboardworks again.routes/web.php:59defines a catch-all fallback that returns JSON for any unmatched web route:In a browser this renders as a bare JSON blob rather than a page, which is what "cannot find the page" looks like from the user's side.
Desired behaviour
/./rather than dead-ending./already redirects todashboard(routes/web.php:15), and the auth middleware sends guests to the login screen — so the redirect lands the user somewhere sensible in both cases.Scope
/api/v1/*endpoints must keep returning JSON for 404s and auth failures in all cases — API clients depend on the JSON contract and must not be redirected.Notes
authmiddleware (routes/web.php:20-37), which resolves to theloginroute fromroutes/auth.php. The gap is the fallback behaviour and the browser-facing 404, not the auth guard.redirectGuestsTo/redirectToconfiguration exists inbootstrap/app.phporapp/— the framework defaults are in play.Acceptance criteria
/././(and onward to login).GET /api/v1/<nonexistent>still returns a JSON 404./api/v1/*request still returns a JSON error response, not a redirect.Attempted 2026-08-13, reverted and moved to backlog. No code landed. Recording the investigation so the next attempt does not start cold.
The fix is not as simple as changing the fallback
1.
/api/v1/*has no fallback of its own — unmatched API routes hit the web fallback.Verified by matching against the router:
/api/v1/nonexistentresolves to the closure inroutes/web.phpwithwebmiddleware, becauseroutes/api.phpdefines noRoute::fallback(). Changing the web fallback toredirect('/')on its own therefore breaks acceptance criterion 4 —GET /api/v1/<nonexistent>would start redirecting instead of returning JSON. The API needs its own fallback first.2.
expectsJson()is not a safe discriminator.An
/api/v1/*request without anAccept: application/jsonheader returnsexpectsJson() === false. Any fix that branches on content negotiation will redirect API clients that omit the header, breaking criterion 5. The reliable discriminator is the path prefix, not the Accept header. Worth a test for the header-less case specifically — it is the real regression risk and is not currently covered.3. Acceptance criterion 3 is unimplementable as written.
Setting
redirectGuestsTo('/')produces an infinite redirect loop:Because
/immediately redirects todashboard, which is itself behindauth, sending guests to/cannot terminate. Laravel's default (/login) terminates precisely because/loginsits behindguestmiddleware instead.This criterion needs a decision before the ticket is picked up again. Either:
/login), which reaches the same end state in fewer hops; or/behave differently for guests (serve something, or redirect tologinwhen not authenticated) so it is a valid landing point.The other four criteria are achievable.
Blocker discovered
tests/Feature/ApiAccessTest.phphangs indefinitely — includingtest_health_endpoint_is_accessible, which merely callsGET /health. Reproduced on a clean checkout with no local changes, after a database container restart, whileFeedsTest(21 tests) andChannelsTest(26 tests) both pass in ~3s against the same database. So it is specific to this test file, not the DB and not the changes attempted here.That needs diagnosing before #135 can be verified at all, since
ApiAccessTestis where its coverage belongs. It may deserve its own ticket.Suggested approach for next time
ApiAccessTesthang first — it blocks verification of anything hereRoute::fallback()inside thev1prefix group inroutes/api.php, returning the existing JSON bodyredirect('/')redirectGuestsTo/api/v1/*case explicitlyNote that
ApiAccessTest::test_fallback_route_returns_api_messagecurrently pins the behaviour this ticket calls a bug, and will need rewriting rather than extending.