TerrePorter's avatar

Custom error handler laravel 11

I’m trying to set up a custom error handler in my project. I’m using nwidart/laravel-modules to create modules and I want each one to handle their own errors. So I have set up a way to load custom error responses from each model. This appears to work on the page as when I go to admin it redirects me to the login page, which is what the custom error handler is doing. However, when I run artisan commands I get an error message.

[Illuminate\Contracts\Debug\ExceptionHandler] is not instantiable.

If I comment out the code in the AppServiceProvider it works. I also commented out the withExceptions in the app.php.

In the appServiceProvider in the main code, I have added the following to register a custom error handler.

  public function register(): void
    {
        $this->app->singleton(
            \Illuminate\Contracts\Debug\ExceptionHandler::class,
            \App\Exceptions\Handler::class
        );

        $using ??= fn () => true;

        $this->app->afterResolving(
            \Illuminate\Foundation\Exceptions\Handler::class,
            fn ($handler) => $using(new Exceptions($handler)),
        );
    }

Anyone have some ideas?

0 likes
4 replies
LaryAI's avatar
Level 58

To set up a custom error handler in Laravel, especially when using the nwidart/laravel-modules package, you need to ensure that your custom error handler is correctly registered and that it doesn't interfere with the default Laravel behavior, especially when running Artisan commands.

The error message [Illuminate\Contracts\Debug\ExceptionHandler] is not instantiable suggests that there might be an issue with how the custom error handler is being registered or resolved.

Here's a step-by-step solution to address this issue:

  1. Custom Exception Handler: Ensure that your custom exception handler extends the default Laravel exception handler.
namespace App\Exceptions;

use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
use Throwable;

class Handler extends ExceptionHandler
{
    // Your custom logic here

    public function render($request, Throwable $exception)
    {
        // Custom error handling logic
        return parent::render($request, $exception);
    }
}
  1. Service Provider Registration: Modify your AppServiceProvider to correctly register the custom exception handler.
namespace App\Providers;

use Illuminate\Support\ServiceProvider;
use App\Exceptions\Handler;
use Illuminate\Contracts\Debug\ExceptionHandler as ExceptionHandlerContract;

class AppServiceProvider extends ServiceProvider
{
    public function register(): void
    {
        $this->app->singleton(ExceptionHandlerContract::class, Handler::class);
    }

    public function boot(): void
    {
        // Any additional boot logic
    }
}
  1. Module-Specific Error Handling: If you want each module to handle its own errors, you can create a custom exception handler for each module and register it within the module's service provider.

For example, in a module's service provider:

namespace Modules\YourModule\Providers;

use Illuminate\Support\ServiceProvider;
use Modules\YourModule\Exceptions\Handler as ModuleHandler;
use Illuminate\Contracts\Debug\ExceptionHandler as ExceptionHandlerContract;

class YourModuleServiceProvider extends ServiceProvider
{
    public function register(): void
    {
        $this->app->singleton(ExceptionHandlerContract::class, ModuleHandler::class);
    }

    public function boot(): void
    {
        // Any additional boot logic
    }
}
  1. Ensure Compatibility with Artisan Commands: Make sure that your custom exception handlers are not interfering with the default behavior of Artisan commands. This can be done by ensuring that the custom logic is only applied to HTTP requests and not to console commands.

In your custom exception handler, you can check if the request is an HTTP request:

namespace App\Exceptions;

use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
use Throwable;

class Handler extends ExceptionHandler
{
    public function render($request, Throwable $exception)
    {
        if ($this->isHttpRequest($request)) {
            // Custom error handling logic for HTTP requests
        }

        return parent::render($request, $exception);
    }

    protected function isHttpRequest($request)
    {
        return $request instanceof \Illuminate\Http\Request;
    }
}

By following these steps, you should be able to set up a custom error handler for your Laravel application and ensure that it works correctly with both HTTP requests and Artisan commands.

1 like
tomassycle's avatar

@TerrePorter Hi, did you find a solution? I have this working in Laravel 10, but looking to upgrade to Laravel 11 and the handler seems to be registered in a very different way

TerrePorter's avatar

@tomassycle Sort of.

I overwrote the error contract with my own class.

use Illuminate\Contracts\Debug\ExceptionHandler as ExceptionHandlerContract;
$this->app->singleton(ExceptionHandlerContract::class, Handler::class);

In my setup I was trying to make modules have their own error handling but was unable to acomplish that.

I did not remove the bootstrap code about error handling as it caused errors, i just didnt use it.

In the handler I have something like this.


use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
use Throwable;

class Handler extends ExceptionHandler
{


    public function render($request, Throwable $exception)
    {
        if ($this->isHttpRequest($request)) {
            // Custom error handling logic for HTTP requests
        }

        return parent::render($request, $exception);
    }
/**
     * Register the exception handling callbacks for the application.
     */
    public function register(): void
    {
        $this->reportable(function (Throwable $e) {
            //
        });

or in this format as an example,

$this->renderable(function (\Spatie\Permission\Exceptions\UnauthorizedException $e, $request) {
            return redirect()->route('login');
});

This seems to work, though its not very elequent.

1 like

Please or to participate in this conversation.