t4mer@notebook

// problem · 20 may 2026 · 1 min

Laravel authentication error returning HTML instead of JSON

The API client expected JSON. Laravel thought it was talking to a browser.

Time wasted: An embarrassing amount of time

Problem

An unauthenticated or validation-failed API call returned an HTML login page or a Blade error, not JSON.

Environment

Laravel API routes / middleware HTTP client expecting JSON

Symptoms

HTTP clients showed a pile of HTML. Postman sometimes looked fine because Accept was application/json. Frontend “API error” parsers choked on <.

Expected

A JSON body with 401 or 422.

Investigation

Checked the route group (web vs api). Dumped request headers. Looked at Exception Handler / middleware expecting JSON.

Things I tried

Added more try/catch in the controller. The exception never reached my catch; the framework rendered a web response first.

Root cause

Missing or wrong Accept header, a route inside the web stack, or an exception handler that redirects guests to login. Laravel is helping the browser. Your client is not a browser.

Solution

Send Accept: application/json. Put the route on the API stack. Teach the exception handler to honour expectsJson().

Why it worked

Content negotiation. Accept tells the application which representation to use when it fails. Without it, the default is often HTML.

Lesson

If the body starts with <, you do not have a JSON bug yet. You have a negotiation bug.

This is a class of bug I have hit more than once. It is not a story about one private codebase. The HTML is almost never your controller being witty. It is the framework being helpful in the wrong direction.

Found something wrong?

These notes can be incomplete, or wrong in a different environment. Suggest a correction on GitHub or email me at me@t4mer.net.

// related