Skip to content

Laravel error

Laravel: Route [login] not defined

The error

Route [login] not defined.

An unauthenticated request reached a guarded route, and the framework tried to redirect to a named route your application does not have. The error is about the redirect, not about authentication.

The error

Symfony\Component\Routing\Exception\RouteNotFoundException

Route [login] not defined.

Thrown from inside the authentication middleware, usually with a stack trace that mentions Authenticate::redirectTo or UrlGenerator::route.

What it means

This is not a failure to authenticate. Authentication already failed - that part worked correctly. What broke is what happened next.

When the auth middleware rejects a request it has to decide what to send back, and for a browser the answer is a redirect to the login page. It finds that page by asking the router for a route named login. Your application does not have one, so the router throws.

So the real question is not "why is authentication failing" but "why is this request being treated as a browser request".

If you are building an API

The usual case, and the usual cause is a missing header.

The middleware decides between a redirect and a 401 by asking whether the request expects JSON, which it reads from Accept. A client sending Accept: application/json gets a clean 401. A client sending nothing, or */*, looks like a browser and gets sent looking for a login page.

Fix it on the client where you can - it is one header and it is correct anyway:

Accept: application/json

And fix it on the server so it cannot happen again, because you do not control every client:

// bootstrap/app.php
->withMiddleware(function (Middleware $middleware) {
    $middleware->redirectGuestsTo(fn () => null);
})

Returning null means there is no redirect target, so the framework raises an AuthenticationException and the handler turns it into a 401 with a JSON body. That is the right response for an API regardless of what the caller sent.

Where an application serves both a web interface and an API, make it conditional rather than global:

$middleware->redirectGuestsTo(
    fn (Request $request) => $request->is('api/*') ? null : route('web.login')
);

If you do have a login page

Then the route exists and the name does not. Check:

php artisan route:list --name=login

Empty output, and one of these applies.

The route has no name. A route defined as Route::get('/login', [LoginController::class, 'show']) is reachable and anonymous. Add ->name('login').

The name is different. auth.login, user.login, signin. The framework looks for exactly login, so either rename the route or tell the middleware what your name is, using the callback above.

The route is behind a prefix or a group that is not loaded. A login route inside a route file that is only registered for one domain, or a group whose condition is false in this environment, will not be in the list.

The route cache is stale. Built before the route existed:

php artisan route:clear

The variant worth recognising

The same error with [password.request], [verification.notice] or [register] in the brackets is the same problem in a different feature. Password reset, email verification and registration each assume a named route that a starter kit would have created and a hand-rolled auth system did not.

The fix is the same: provide the name, or tell the framework what your name is.

The commonest way to meet this is not a missing route at all. It is a session that expired and a 419 that redirects towards a login page whose route was never named.

On an API it is usually the wrong middleware: a JSON client sent towards a login page it cannot render. The token package you are on decides what should happen instead, and getting that boundary right is most of what API work is.

Related questions

Why does an API route try to redirect at all?
Because the middleware decides between a redirect and a 401 by looking at whether the request expects JSON, and it decides that from the Accept header. A client that does not send Accept: application/json looks like a browser, so it gets browser treatment.
We have no login page and never will. What is the right fix?
Tell the middleware to stop looking for one. Returning null from the redirect callback makes the framework throw an AuthenticationException instead, which becomes a 401 with a JSON body - the correct answer for an API and the one clients can actually handle.
It appears in tests but not when we use the application.
Almost always the Accept header again. Browsers and most HTTP clients send one; a test helper calling get() rather than getJson() does not, so the test takes the browser branch that your real clients never touch.
Could this be a route caching problem?
It can. A cached route file built before the login route existed will not contain it, and the name lookup fails even though the route is in your files. Clearing the route cache rules this out in one command, and it is worth doing before changing any code.
Call us+1 848 272 7583WhatsApp+90 850 308 5436Emailinfo@codefacture.comContact page