Courses

Handling Exceptions and Errors in Laravel

Catching Specific Exceptions

You see quite a lot of examples of try-catch with catching a regular Exception class, like this:

use Exception;
 
try {
$request->user()->addMediaFromRequest('avatar')->toMediaCollection();
} catch (Exception $e) {
Log::debug($e->getMessage());
}

But try-catch is way more helpful when catching a specific Exception. Laravel and 3rd party packages often offer us actionable Exception classes for specific errors.

For example, when uploading a picture, you might have some issues with resizing the image. For that, there's a specific InvalidManipulation.

use Spatie\Image\Exceptions\InvalidManipulation;
use Exception;
 
try {
$request->user()->addMediaFromRequest('avatar')->toMediaCollection();
} catch (InvalidManipulation $manipulationException) {
Log::debug($manipulationException->getMessage());
 
Log::info("Please re-run the resizing on user avatar #" . $request->user()->id);
}

Notice: try-catch doesn't mean ending the whole method if an Exception happens. In the example above, even if the resizing error occurs, you may still want everything to continue and upload the original, just logging the error to fix it manually in the future.

Let's look at other examples.


Specific and General Exception: Why Not Both

You may catch not only a specific Exception but also add multiple catch blocks, with the general Exception class as the last one.

use Illuminate\Validation\ValidationException;
use Spatie\Image\Exceptions\InvalidManipulation;
use Exception;
 
try {
$request->user()->addMediaFromRequest('avatar')->toMediaCollection();
} catch (InvalidManipulation $manipulationException) {
Log::debug($manipulationException->getMessage());
 
Log::info("Please re-run the resizing on user avatar #" . $request->user()->id);
} catch (Exception $e) {
Log::debug($e->getMessage());
 
throw ValidationException::withMessages([
'avatar' => __('Selected avatar image failed to upload. Try again or select a different image.'),
]);
}

This way, we handle the InvalidManipulation exception differently than the rest of the exceptions, which allows us to upload the file and show the success screen to the user while still getting log information:

[2023-05-16 08:55:46] production.DEBUG: Width or height or both must be provided
[2023-05-16 08:55:46] production.INFO: Please re-run the resizing on user avatar #1

And here's the uploaded image:


Multiple Exceptions in the Same Catch Block

What if you want to catch a few specific exceptions and perform the same action if an error happens? Would you write a few catch blocks?

try {
$request->user()->addMediaFromRequest('avatar')->toMediaCollection();
} catch (InvalidManipulation $manipulationException) {
Log::debug($manipulationException->getMessage());
 
Log::info("Please re-run the resizing on user avatar #" . $request->user()->id);
} catch (FileNotFoundException $fileNotFoundException) {
Log::debug($fileNotFoundException->getMessage());
 
Log::info("Please re-run the resizing on user avatar #" . $request->user()->id);
} catch (Exception $e) {
Log::debug($e->getMessage());
 
throw ValidationException::withMessages([
'avatar' => __('Selected avatar image failed to upload. Try again or select a different image.'),
]);
}

Such repeating is not necessary. If more than one Exception is handled with identical code, you can combine them into one catch block using the | symbol.

try {
$request->user()->addMediaFromRequest('avatar')->toMediaCollection();
} catch (InvalidManipulation|FileNotFoundException $exception) {
Log::debug($exception->getMessage());
 
Log::info("Please re-run the resizing on user avatar #" . $request->user()->id);
} catch (Exception $e) {
Log::debug($e->getMessage());
 
throw ValidationException::withMessages([
'avatar' => __('Selected avatar image failed to upload. Try again or select a different image.'),
]);
}

As you can see, we are now catching both the InvalidManipulation and FileNotFoundException exceptions in the same catch block. This way, we can handle them the same way but still have different handling for other exceptions.

No comments or questions yet...