Error Pages

Error Handling and Custom HTTP Error Pages

The kernel's try/catch hands uncaught exceptions to the handler, which reports them (Logging) and renders them; withExceptions() tunes both with report(), render(), dontReport() and throttle(). APP_DEBUG=true shows stack traces, so never enable it in production. abort(404) throws an HttpException, and a view named after the status code in resources/views/errors/ replaces the stock page:

resources/views/errors/404.blade.phpHTML
<!doctype html>
<title>Not found | {{ config('app.name') }}</title>
<h1>We could not find that page</h1>
<p>{{ $exception->getMessage() ?: 'The address may be mistyped.' }}</p>

Here /orders/7 calls abort(404, "Order 7 does not exist.") via abort_unless(), and /checkout throws a RuntimeException, with APP_DEBUG=false:

A custom 404 page and a JSON 500Shell
curl -s localhost:8302/orders/7 | grep '<p>'
curl -s -H 'Accept: application/json' localhost:8302/checkout; echo
Output
<p>Order 7 does not exist.</p>
{
    "message": "Server Error"
}

The 500 hides its message and trace. 4xx.blade.php and 5xx.blade.php catch other codes, and php artisan vendor:publish --tag=laravel-errors copies the stock pages. Maintenance mode is a planned 503: php artisan down writes storage/framework/down, and the global PreventRequestsDuringMaintenance middleware answers every request except /up:

Taking the bookshop down with a bypass secretShell
php artisan down --secret=preview-7f3k --retry=60
curl -s -i localhost:8302/products/42 | grep -iE '^(HTTP|retry-after)'
Output
...
   INFO  You may bypass maintenance mode via [http://localhost:8000/preview-7f3k].
HTTP/1.1 503 Service Unavailable
retry-after: 60

That URL sets a laravel_maintenance cookie for normal browsing. The framework still boots for every request; down --render="errors::503" instead pre-renders the page into storage/framework/maintenance.php, which index.php serves before the autoloader (the tracer logged nothing). php artisan up ends maintenance.