To create a custom error page in Laravel 13, add a Blade file named after the HTTP status code in resources/views/errors, such as 404.blade.php or 500.blade.php. Laravel renders that view automatically whenever the matching error happens.
You can also publish the default templates, add fallback pages for whole ranges like 4xx and 5xx, and return JSON for API routes. This guide covers each step.
What do I need first?
- Laravel 13 (current stable at the time of writing) on a supported PHP version.
APP_DEBUG=falseto see your custom pages. When debug is on, Laravel shows its detailed error screen for exceptions instead.
How do I create a custom 404 page?
Create the file resources/views/errors/404.blade.php.
@extends('layouts.app')
@section('content')
<div class="text-center">
<h1>404</h1>
<p>Sorry, we could not find that page.</p>
<a href="{{ url('/') }}">Back to the home page</a>
</div>
@endsectionReplace layouts.app with your own layout. If your layout needs data from a controller or a view composer that may fail, use a plain HTML page for error views, because an error inside the error page makes things worse.
How do I show the exception message?
The HttpException raised by abort() is passed to the view as $exception.
{{-- resources/views/errors/403.blade.php --}}
<h1>403</h1>
<p>{{ $exception->getMessage() ?: 'You are not allowed to view this page.' }}</p>abort(403, 'This report is only for administrators.');Show messages only for errors you wrote on purpose. Never print internal exception text from unexpected failures such as 500 errors.
Which status codes should I customize?
- 404 page not found
- 403 forbidden
- 419 page expired (a missing or expired CSRF token)
- 429 too many requests
- 500 server error
- 503 maintenance mode or service unavailable
How do I use the default templates as a starting point?
php artisan vendor:publish --tag=laravel-errorsThis copies Laravel's built-in error views into resources/views/errors. Edit them to match your brand.
How do I add fallback pages?
Create 4xx.blade.php and 5xx.blade.php in the same folder. Laravel uses them when no file exists for the exact code. They do not replace the dedicated pages for 401, 402, 403, 404, 419, 429, 500 and 503, so create those individually if you want to change them.
How do I return JSON for API routes?
Laravel renders JSON automatically when the client sends an Accept: application/json header. To force a custom body for a specific exception, use bootstrap/app.php.
use Illuminate\Http\Request;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
->withExceptions(function (Exceptions $exceptions): void {
$exceptions->render(function (NotFoundHttpException $e, Request $request) {
if ($request->is('api/*')) {
return response()->json(['message' => 'Record not found.'], 404);
}
});
})If the closure returns nothing, Laravel falls back to its default rendering, so web routes still use your Blade 404 page.
How do I make a custom exception render its own page?
namespace App\Exceptions;
use Exception;
use Illuminate\Http\Request;
class PaymentFailedException extends Exception
{
public function render(Request $request)
{
return response()->view('errors.payment-failed', [], 402);
}
}Throw it anywhere with throw new PaymentFailedException();. Laravel calls the render() method on the exception itself.
What are the common mistakes?
- Debug mode left on. You see the debug screen, not your page. Set
APP_DEBUG=falseto test. - Wrong file name or folder. It must be
resources/views/errors/404.blade.php. - Cached views. Run
php artisan view:clearafter edits on a server. - Heavy layouts. If the layout queries the database and the database is down, the 500 page also fails. Keep error views simple.
- Using 4xx.blade.php for 404. Dedicated codes need dedicated files.
How do I test the pages?
public function test_unknown_page_shows_custom_404(): void
{
$this->get('/this-page-does-not-exist')
->assertNotFound()
->assertSee('could not find that page');
}To check a 500 page by hand, add a temporary route that throws an exception, load it with APP_DEBUG=false locally, then remove the route.
FAQ
Why do I still see Laravel's default 404?
Usually the file name is wrong or view caches are stale. Check the path and run php artisan view:clear.
Can I use a Blade component in error pages?
Yes, but keep it free of database calls. Error pages should render even when parts of the app are broken.
How do I change the maintenance mode page?
Create resources/views/errors/503.blade.php. Laravel uses it when the application is down.



