About Error Handling in Laravel
web-application-framework laravel
I investigated error handling in Laravel and tried out how to log and handle responses when exceptions occur.
Reference
Environment
- Laravel 11
Table of Contents
Preparation
Before testing error handling, create a custom exception class that extends Laravel’s base Exception
class.
Run the following Artisan command to generate the TestException
class:
php artisan make:exception TestException
This will create the file: app/Exceptions/TestException.php
.
Logging Exceptions with report
By default, exceptions are logged according to the project’s logging configuration.
This behavior can be customized in bootstrap/app.php
or in individual Exception
subclasses.
Defining in app.php
To define logging behavior in bootstrap/app.php
, use the report
method inside the closure passed to withExceptions
.
Edit bootstrap/app.php
as follows:
return Application::configure(basePath: dirname(__DIR__))
->withRouting(
...
)
->withMiddleware(function (Middleware $middleware) {
...
})
->withExceptions(function (Exceptions $exceptions) {
// Add the following
$exceptions->report(function (TestException $e) {
// Log 'test'
Log::error('test');
});
})->create();
This configuration logs the message ‘test’ whenever a TestException
is thrown.
You can specify the exception type using the closure’s type hint.
To disable the default logging behavior, either use stop()
or return false
from the closure:
->withExceptions(function (Exceptions $exceptions) {
$exceptions->report(function (TestException $e) {
// Log 'test'
Log::error('test');
})->stop(); // Add stop()
})
->withExceptions(function (Exceptions $exceptions) {
$exceptions->report(function (TestException $e) {
// Log 'test'
Log::error('test');
return false; // Add 'return false'
});
})
Defining in the Exception Class
You can also define logging behavior within the exception class itself by overriding the report
method.
In app/Exceptions/TestException.php
, add:
...
class TestException extends Exception
{
// Add the following
public function report(): void
{
// Log 'test'
Log::error('test');
}
}
This logs ‘test’ whenever a TestException
is thrown.
If you want to apply custom logic based on certain conditions, you can return true
or false
from the report
method.
Returning true
uses the custom logic; returning false
falls back to the default handler.
public function report(Request $request): bool
{
$user = $request->user();
if ($user === null) {
// Use default handling if user is not authenticated
return false;
}
if ($user->id % 2 === 0) {
// Log if user ID is even
Log::error('test');
return true;
}
// Use default handling if user ID is odd
return false;
}
Customizing Responses with render
By default, Laravel inspects the HTTP request’s Accept
header and automatically returns either an HTML or JSON response when an exception occurs.
You can customize this behavior in bootstrap/app.php
or in individual exception classes.
Defining in app.php
Edit bootstrap/app.php
and use the render
method inside the closure passed to withExceptions
.
app.php
:
return Application::configure(basePath: dirname(__DIR__))
->withRouting(
...
)
->withMiddleware(function (Middleware $middleware) {
...
})
->withExceptions(function (Exceptions $exceptions) {
// Add the following
$exceptions->render(function (TestException $e) {
return response()->json(['error_message' => $e->getMessage()]);
});
})->create();
This returns a JSON response with the error message when a TestException
is thrown.
Make sure the render
method returns an instance of Illuminate\Http\Response
class or a subclass of it, typically created using the response
helper.
If the closure returns nothing, Laravel will use its default response handling.
Defining in the Exception Class
You can override the render
method in a custom exception class to define your own response logic.
In app/Exceptions/TestException.php
, add:
...
class TestException extends Exception
{
// Add the following
public function render(): JsonResponse
{
return response()->json(['error_message' => $this->message]);
}
}
This returns a JSON response containing the exception message whenever the exception is thrown.
You can also use conditional logic in render
to switch between custom and default responses by returning false
:
public function report(Request $request): bool
{
$user = $request->user();
if ($user === null) {
// Use default response
return false;
}
if ($user->id % 2 === 0) {
// Custom response
return response()->json(['error_message' => $this->message]);
}
// Use default response for odd IDs
return false;
}