★ Ignition: a new error page for Laravel
Tags: laravel, php
Published: 2020-01-02 23:35:52

---
title: ★ Ignition: a new error page for Laravel
published: true
date: 2019-08-30 15:03:38 UTC
tags: laravel, php
canonical_url: https://freek.dev/1441-ignition-a-new-error-page-for-laravel
---

Today at Laracon EU, [Marcel Pociot](https://twitter.com/marcelpociot) and I unveiled [Ignition](https://flareapp.io/docs/ignition-for-laravel/introduction), a beautiful new error page for Laravel. It is the new default error screen in Laravel 6 and you can manually install it into Laravel 5 applications. In this blog post, I'd like to tell you all about it.

## Starting the ignition #

[My team](https://spatie.be) and I love to [create packages](https://spatie.be/open-source/packages). But we're not the only ones that are very active in creating open-source stuff for the Laravel and PHP community. My friend [Marcel Pociot](https://twitter.com/marcelpociot) and his company [Beyond Code](https://beyondco.de/) are contributing [a lot](https://github.com/beyondcode) too. Combined, our teams have made more than 300 packages which have been downloaded over 50 million times.

From time to time Marcel and I ask some feedback and help each other out. Last year Marcel and I even made a package together: [laravel-websockets](https://docs.beyondco.de/laravel-websockets/). This package provides an entire server-side websockets implementation. It's a drop-in replacement for Pusher.

We had a lot of fun programming it as a duo, so it was only logical that we'd do another one together. We had a couple of ideas. One of them was error reporting.

At the time, I visited a [workshop on Elm](https://www.eventbrite.com/e/womencodebe-elm-workshop-tickets-54052124359?utm_source=eb_email&utm_medium=email&utm_campaign=reminder_attendees_48hour_email&utm_term=eventname) given by my buddy [Steven Vandevelde](https://twitter.com/icidasset). Something that stuck with me was that Elm has very nice error screens.

This convinced us we could improve the error screens for the Laravel ecosystem as well. Very early on Marcel and I knew that if we wanted to solve this problem right, we'd need a lot of time and help from our teams. So, we talked a lot with everybody involved, founded a new firm (called Facade) together and started working on this with our team members.

Marcel and I may be the public figures, but we couldn't have done this without our teams. A lot of good ideas came from them as well. Here's [a twitter list with all Spatie team members](https://twitter.com/spatie_be/lists/spatie/members), and here's the twitter account of Beyond Code's [Sebastian](https://twitter.com/seb_sebsn). Make sure to follow them.

We created a new error tracking service called Flare (you can read more about that in [this blog post](https://freek.dev/1442-flare-a-new-error-tracker-built-for-laravel-apps) and a beautiful new error page called Ignition.

In this blog post I'm going to tell you all about Ignition.

## From Elm to Ignition #

Let's take a look at a few error screens of Elm. Notice that an error screen in Elm doesn't focus solely on the error, but on the solution as well.

![Elm error](https://freek.dev/uploads/media/ignition-2019/elm1.png)

Let's take a look at another one. This one provides links to the documentation.

![Elm error](https://freek.dev/uploads/media/ignition-2019/elm2.png)

Now let's look at what we have in PHP by default. Without a framework, PHP offers you this. You only get the error: no stack trace, no request or application details.

![PHP error](https://freek.dev/uploads/media/ignition-2019/php-error.png)

Symfony's error page is slightly better, it shows you the stack trace, but it isn't very helpful.

![Symfony error](https://freek.dev/uploads/media/ignition-2019/symfony-error.png)

The following screenshot is Whoops, which is the standard in Laravel 5. It's way better than the default of Symfony, showing you the stack trace and some info around the request. Even though Whoops is the default in Laravel, it's a framework agnostic screen. It only shows generic info.

![Whoops error](https://freek.dev/uploads/media/ignition-2019/whoops-error.png)

And here's a screenshot of Ignition, the new error screen that we built. Because it's Laravel specific, we can do a lot of cool things.

![Ignition error](https://freek.dev/uploads/media/ignition-2019/ignition-error.png)

## Exploring Ignition #

Let's explore all the neat things in Ignition. It's open source, and you can explore the code [here](https://github.com/facade/ignition).

If you have an error in your views, this is how whoops displays them. Notice that the exception message does not fit the allocated space. You have to hover over it to see it fully. In the stack trace you see that compiled Blade views and content is used. This makes it hard to track down which Blade view file contains the error, and the view content itself is not readable.

![Whoops view error](https://freek.dev/uploads/media/ignition-2019/view-error-whoops.png)

Ignition is a Laravel specific error page. So, it can hook into the framework to display the uncompiled view path and your Blade view. There is also enough room at the top to show the entire exception page, no extra clicks required. We also only display the application frames by default because those are the frames you're probably interested in.

![Ignition view error](https://freek.dev/uploads/media/ignition-2019/view-error-ignition.png)

If you click on that pencil icon next to the filename on the right hand of the stack trace tab, we'll automatically open the file in your favorite editor. By default it's PhpStorm. You can configure it to your favorite editor in the `ignition` config file.

Notice that little "Telescope" link at the top right corner? We'll only display that if you've installed [Laravel Telescope](https://laravel.com/docs/5.8/telescope), a first-party debug assistant. If you click that link, you'll be taken to the exception in Telescope in which the error occurred.

## Dark mode #

If our default error screen is too bright for your taste, you'll be happy to know that our error page has a dark mode as well.

![Dark mode](https://freek.dev/uploads/media/ignition-2019/dark-mode.png)

## Ignition tabs #

Let's explore the tabs displayed on an Ignition page.

### The request tab #

![Request tab](https://freek.dev/uploads/media/ignition-2019/request-tab.png)

Next to the "Stack trace" tab, you'll see the "Request" tab. It displays all the info you'd expect about the request.

### The app tab #

![App tab](https://freek.dev/uploads/media/ignition-2019/app-tab.png)

The "App" tab is where it gets a little bit more interesting. This tab displays Laravel specific information about your application. First we show you information about the route where the exception happened. This includes the controller which was executed from the current request - if available - as well as the route name.

Another cool feature is the ability to inspect your route parameters.

Let's say you have a route definition like this:

```
Route::get('/posts/{post}', function (Post $post) {
	//
});
```

When you encounter an exception on this route, we will show you the `toArray` representation of that `post` model in Ignition as part of your route parameters. The same goes for "simple" route parameters that do not require any bindings. This is a really nice way to easily see what information Laravel received for this particular route.

After the route parameters, we also show you the list of middlewares that were used within this request.

Next we have the "View" section. If the exception occurred within a view, we will show you the view name here. Even more: we’ll also give you a list of all the data that was passed to the view.

### The user tab #

![User tab](https://freek.dev/uploads/media/ignition-2019/user-tab.png)

The "User" tab contains more info around who's using the app and which browser is used.

### The context tab #

![Context tab](https://freek.dev/uploads/media/ignition-2019/context-tab.png)

In the "Context" tab we display information on your repo (where is the repo located, what's the checkout commit hash) and the environment (which versions of PHP and Laravel are you using).

### The debug tab #

![Debug tab](https://freek.dev/uploads/media/ignition-2019/debug-tab.png)

In the "Debug" tab we show you things that took place before the exception happened. Things like queries, log, and dumps. Next to a dump, we also display the filename of where you put that `dump` statement. A click on the pencil icon takes you right to that file and correct line number in your favorite editor.

## Suggesting solutions #

Let's take a look at another error. This time we're going to forget importing a class. This is how the Ignition page for such an error looks like.

So Ignition sees that the exception is about a class that is not found. It will try to figure out if there is a class with that name in another namespace. If there is one, it'll suggest to importing it.

![Missing import solution](https://freek.dev/uploads/media/ignition-2019/import-missing-error.png)

Ignition ships with a bunch of solutions for common problems. Here's one for when a Blade view is not found.

![Invalid view](https://freek.dev/uploads/media/ignition-2019/invalid-view.png)

You can also add solution suggestions to your exceptions. You should let your exception implement the `Facade\IgnitionContracts\ProvidesSolutions` implementation. It'll require you to add a `getSolution` function. Here's a possible implementation.

```php
namespace App\Exceptions;

use Exception;
use Facade\IgnitionContracts\Solution;
use Facade\IgnitionContracts\BaseSolution;
use Facade\IgnitionContracts\ProvidesSolution;

class CustomException extends Exception implements ProvidesSolution
{
    public function getSolution(): Solution
    {
          return BaseSolution::create("You're doing it wrong")
            ->setSolutionDescription('You are obviously doing something wrong. Check your code and try again.')
            ->setDocumentationLinks([
                'Laracasts' => 'https://laracasts.com',
                'Use Flare' => 'https://flareapp.io',
            ]);
    }
}
```

This is how throwing that exception would look like in Ignition.

![Custom solution](https://freek.dev/uploads/media/ignition-2019/custom-solution.png)

## Running solutions #

In addition to merely suggestion solutions, we can also run them ?. Imagine that, for instance, you've forgotten to set your app key. Here's how that error looks like in Ignition.

![App key missing](https://freek.dev/uploads/media/ignition-2019/app-key-missing.png)

If you click the "Generate app key" button, we'll generate and set the app key in the background.

![App key generated](https://freek.dev/uploads/media/ignition-2019/app-key-generated.png)

After refreshing the page, your application will work (unless it contains other exceptions).

Here's a video where you can see a couple of runnable solutions in action. We're going to try to save a model, but we forgot to generate the app key and create a DB. The solutions will generate an app, put the right DB credentials in place, and run our migrations.

<iframe width="560" height="315" src="https://www.youtube.com/embed/EZu0-CwTU9Q" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>

You can create your runnable solutions by letting your exception implement `Facade\IgnitionContracts\ProvidesSolution`, much like the non-runnable solution). The `getSolution` method can both return runnable and non-runnable solutions.

```php
namespace App\Exceptions;

use Exception;
use Facade\IgnitionContracts\ProvidesSolution;

class CustomException extends Exception implements ProvidesSolution
{
    public function getSolution(): Solution
    {
          return new MyRunnableSolution();
    }
}
```

Here's the example implementation of `MyRunnableSolution`.

```php
namespace App\Solutions;

use Facade\IgnitionContracts\RunnableSolution;

class MyRunnableSolution implements RunnableSolution
{
    public function getSolutionTitle(): string
    {
        return 'You are doing it wrong';
    }

    public function getSolutionDescription(): string
    {
        return 'You are doing something wrong, but we can fix it for you.';
    }

    public function getDocumentationLinks(): array
    {
        return [];
    }

    public function getSolutionActionDescription(): string
    {
        return 'To fix this issue, all you need to do is press the button below.';
    }

    public function getRunButtonText(): string
    {
        return 'Fix this for me';
    }

    public function run(array $parameters = [])
    {
        // Your solution implementation
    }

    public function getRunParameters(): array
    {
        return [];
    }
}
```

This is how throwing the `CustomException` will look like in Ignition.

![Custom runnable solution](https://freek.dev/uploads/media/ignition-2019/custom-runnable-solution.png)

The `run` function will execute when the user has clicked the `Fix this for me` button.

You can pass parameters from the request where your exception occurred in to the request where the solution will run in. Just let `getRunParameters` return an array. That array will be passed to `run`.

## Making Ignition smarter #

So you have the ability to enhance your own exceptions by using textual or runnable solutions. But sometimes it would be nice to provide solutions for built-in PHP exceptions or even third-party exceptions where you have no control of the code.

We allow you to do this using "Solution Providers". Solution providers are classes that can hook into the solution lookup process from Ignition. When an exception gets thrown and Ignition receives it, your custom solution provider can be called to return one or multiple possible solutions for this exception.

You could for example create a custom "Stack Overflow" solution provider, which will try to find matching stack overflow answers for the given exception and return them as solutions.

We also make use of solution providers in Ignition itself. Here is how one such solution provider looks like:

```php
use Throwable;
use RuntimeException;
use Facade\IgnitionContracts\Solution;
use Facade\Ignition\Solutions\GenerateAppKeySolution;
use Facade\IgnitionContracts\HasSolutionForThrowable;

class MissingAppKeySolutionProvider implements HasSolutionForThrowable
{
    public function canSolve(Throwable $throwable): bool
    {
        if (! $throwable instanceof RuntimeException) {
            return false;
        }

        return $throwable->getMessage() === 'No application encryption key has been specified.';
    }

    public function getSolutions(Throwable $throwable): array
    {
        return [
            new GenerateAppKeySolution()
        ];
    }
}
```

These solution providers can get automatically registered within Ignition like this:

```php
namespace App\Providers;

use App\Solutions\GenerateAppKeySolution;
use Facade\IgnitionContracts\SolutionProviderRepository;
use Illuminate\Support\ServiceProvider;

class YourServiceProvider extends ServiceProvider
{
    /**
     * Register services.
     *
     * @return void
     */
    public function register(SolutionProviderRepository $solutionProviderRepository)
    {
        $solutionProviderRepository->registerSolutionProvider(GenerateAppKeySolution::class);
    }
}
```

Like this, solution providers are going to keep enhancing Ignitions ability to provide solutions for your exceptions and we can't wait to see what the community comes up with!

## Customizing Ignition #

We've made Ignition extensible. You can add new tabs or replace the default ones.

Let's take a look at the [facade/ignition-tinker-tab](https://ignition-tinker-tab) that we provided. The package is a wrapper around [spatie/laravel-web-tinker](https://github.com/spatie/laravel-web-tinker) which allows you to use Artisan tinker in the browser.

With [facade/ignition-tinker-tab](https://ignition-tinker-tab) installed you can use artisan tinker on your error page.

![Tinker tab](https://freek.dev/uploads/media/ignition-2019/ignition-tinker-tab.png)

We've also created a second package, called [facade/ignition-code-editor](https://github.com/facade/ignition-code-editor). This one replaces the default stack trace tab, with a custom one that allows you to edit your code, right on the error screen. Here it is in action.

![Code editor](https://freek.dev/uploads/media/ignition-2019/editor.gif)

To learn how to add custom tabs, visit [the documentation on adding tabs](https://flareapp.io/docs/ignition-for-laravel/adding-custom-tabs).

## Sharing local errors on Flare #

A neat feature of the error page is the ability to share errors with others. Next to the "Debug" tab, there's a share button. Click on it, and a menu will pop up that allows you to choose which information will be shared.

![Share dialog](https://freek.dev/uploads/media/ignition-2019/share-dialog.png)

If you click on it and you'll get shown two URLs.

![Shared error dialog](https://freek.dev/uploads/media/ignition-2019/shared-error-dialog.png)

The public share link is meant to be shared with whoever you want to share your error with. You should keep the admin link to yourself. You can use that link to delete the shared error.

This is what a shared error looks like.

![Shared error](https://freek.dev/uploads/media/ignition-2019/shared-error.png)

## Reporting all errors to Flare #

In the screenshot above, you've probably noticed that the shared error lives on [flareapp.io](https://flareapp.io). Flare is the new Laravel specific exception tracker that we launched together with Ignition.

Most of the features Ignition brings to the table are valid for Flare as well. If you report an error to flare for an exception that has a solution, we'll also display that solution on Flare.

![Shared error](https://freek.dev/uploads/media/ignition-2019/solution.png)

To read more about Flare, head over to [this blog post](https://freek.dev/1442-flare-a-new-error-tracker-built-for-laravel-apps).

## Closing thoughts #

If you want to take a look under the hood how the error page works, head over to [the Ignition repo on GitHub](https://github.com/facade/ignition). The readme of the package lives on [the docs pages of Flare](https://flareapp.io/docs/ignition-for-laravel/introduction).

We've worked for about eight months on this with a team of very talented people. In our opinion, this error page is a significant improvement on the Whoops page you used in Laravel 4 and 5. We hope you like it as much as we do.