Laravel Exceptions: How to Catch, Handle and Create Your Own

Quite often web-developers don’t care enough about errors. If something goes wrong, you often see default Laravel texts like “Whoops, something went wrong” or, even worse, the exception code, which is not helpful at all to the visitor. So I decided to write a step-by-step article of how to handle errors in elegant way and present proper error information to the visitor.

As a side-note: this article will also show an example of creating your own Service with Dependency Injection, and handling exceptions thrown by the service.

Preparation: User Search Task

So we have a really simple example – a form to find a user by their ID.

user search by id

We have two routes:

And a controller with two methods:

Finally, resources/views/users/index.blade.php will present a form:

If we search for existing user and it’s found, we see this result:

Screen Shot 2018-04-23 at 8.05.06 AM

It’s all in resources/views/users/search.blade.php:

Ok, so this is our ideal scenario. But what if the user is not found?

Exception handling

Let’s get out of ideal world. We’re not checking for user existence, we’re only doing this in Controller:

And if user is not found, we will see this:

laravel exception

Or, of course, we can set .env file with APP_DEBUG=false and then the browser will just show blank Whoops, looks like something went wrong. But that still doesn’t give any valuable information to our visitor.

Another quick fix we can make is using User::findOrFail() instead of just find() – then if user is not found, Laravel would show 404 page with text “Sorry, the page you are looking for could not be found.”. But this is a default 404 page for the whole project, so not massively helpful to user, is it?

So we need to catch the errors, process them and redirect back to the form with actual understandable error message.

We need to know the exception type and class name that it would return. In case of findOrFail() it would throw an Eloquent exception ModelNotFoundException, so we need to do this:

Now, let’s actually show an error in Blade:


Screen Shot 2018-04-23 at 8.26.02 AM

Great, we show the error message! But it’s still not ideal, right? Instead of $exception->getMessage() we need to show our own message:


Screen Shot 2018-04-23 at 8.28.18 AM

Moving Error Message Handling into Service

For now, we’ve taken a really simple example of one action in controller – just finding the user. In real application it gets more complicated – usually controller is calling some kind of external service or package method which may fail with different kind of errors.

Let’s create our own service which would essentially do the same thing, but would throw exception, so controller wouldn’t even have to know the message text.

Let’s move our logic into app/Services/UserService.php:

And in Controller, we need to call this service. First, we inject it into __construct() method:

If you are not familiar with dependency injection and how Laravel IOC container works, here’s official documentation or a good article about it.

Now, here’s how our search() method looks:

Notice that we can use $exception->getMessage() again, and all the error validation or message logic is happening within the service – that’s one of the purpose, to separate these actions, controller shouldn’t perform it.

Step Even Further: Creating Our Own Exception Class

Final chapter in this article – even better architecture when your service throws its own exception related to that particular error, and there could be multiple exception classes depending on error. A good example of such architecture is Stripe library, its usage looks like this:

So how can we create our own exception class? Simple, with Artisan command:

Here’s what it would generate in app/Exceptions/UserNotFoundException.php:

Nothing here, right? Let’s fill our exception with some logic.
There could be two methods in this class:

  • report() is used if you want to do some additional logging – send error to BugSnag, email, Slack etc.
  • render() is used if you want to redirect back with error or return HTTP response (like your own Blade file) directly from Exception class

So, for this example we fill our render() method:

Finally, this is how we call this exception then, from Controller:

So, that’s all I wanted to show you about Exception handling and also using Services, as a side-note.

I understand that my example is really simplified, and other people could use Exceptions in a different way, but I hope this article will give an overview of exceptions in general, and reasons WHY you should use them, to show errors to the visitors in elegant way.

More about exceptions and error handling: official Laravel documentation

Want to generate Laravel adminpanel online?
You don't need any packages to do that!

5 thoughts on “Laravel Exceptions: How to Catch, Handle and Create Your Own

  1. Hi,

    nice article, learned a thing or two.

    Just a small note – it’s considered a bad practice to extend your custom exceptions from top level Exception class – it’s advised to rather extend one of lower level ones ( In this particular example, I would perhaps extend the ModelNotFoundException itself.

    Also, for anyone interested in topic further, there’s a great video on how to handle “unhappy path” generally –

    1. Thanks for the comment, Peter, really valuable! Yes, I agree, maybe this exception does look like ModelNotFoundException, but the goal was to show how to create custom exceptions in general. Bad example, perhaps.

  2. First off I want to say thank you for taking the time to write this article!
    I have a couple of questions regarding exceptions and the service class.

    The reason why I avoid exceptions is because the try catch statement makes my code harder to read (I know it’s a stupid reason and I understand the importance of exceptions but that’s the number one thing that stops me from using exceptions everywhere), even in your example the search method in the controller got from:

    public function search(Request $request)
    $user = User::find($request->input('user_id'));
    return view('', compact('user'));


    public function search(Request $request)
    try {
    $user = $this->userService->search($request->input('user_id'));
    } catch (UserNotFoundException $exception) {
    return back()->withError($exception->getMessage())->withInput();
    return view('', compact('user'));

    The initial function has 2 lines of code whereas the function that implements the exception handling has 7 lines of code.
    Is there a way to move the try catch block outside of the search method so that the method can remain at 2 lines of code ?

    Another thing that I find unclear is how do I decide which piece of code is best suited for a Service class.
    I usually use Service classes to store uploaded files or manipulate the request data so that I can persist it in the database, I avoid putting database related code in service classes though.
    Is everything a service ?

    1. 7 lines of code vs 2 lines of code – there’s actually a way to “hide” it from controller, rendering exceptions in Laravel’s Handler.php.
      And in my case the code seems bigger, in real-life projects is more like 50 lines vs 45 lines – not that significant.

      Service classes and code structure – I’ve analyzed a lot of codebases and concluded that there are hundreds of ways to structure, and everyone does what’s best for them individually. My take on this – is that service should take any logic unrelated to routing (which should be in controller) and model properties (settings, relationships, appends etc).

  3. Hi,
    I am not much familiar with the exception handling so please pardon me if am wrong.
    My doubt is, while using our own Exception Class(UserNotFoundException) how does laravel knows our custom exception is occurred from the following code? Don’t we need to throw it? or laravel automatically find the exception and throws it?

    try {
    $user = $this->userService->search($request->input(‘user_id’));
    } catch (UserNotFoundException $exception) {
    return back()->withError($exception->getMessage())->withInput();

Leave a Reply

Your email address will not be published. Required fields are marked *