spatie/laravel-error-solutions
Shows helpful, actionable “solutions” directly on Laravel’s error page, explaining likely causes and fixes. Some solutions are runnable with one click (e.g., generate APP_KEY), speeding up debugging during local development.
Installation:
composer require spatie/laravel-error-solutions
Publish the config file:
php artisan vendor:publish --provider="Spatie\ErrorSolutions\ErrorSolutionsServiceProvider"
First Use Case:
1/0 in a route).PDOException).solutions.php config file.Where to Look First:
config/error-solutions.php (define custom solutions).app/Providers/ErrorSolutionsServiceProvider.php (extend default behavior).resources/views/vendor/error-solutions/errors/solutions.blade.php (customize UI).Defining Solutions:
solutions.php config:
'solutions' => [
'Symfony\Component\Debug\Exception\FatalErrorException' => [
'title' => 'Fatal Error in Production',
'solutions' => [
'Check your PHP error logs for the root cause.',
'Ensure your `APP_DEBUG` is `false` in `.env`.',
],
],
],
'solutions' => [
'Illuminate\Database\QueryException' => function () {
return [
'title' => 'Database Query Failed',
'solutions' => [
"Verify your connection in `.env`: DB_".config('database.connections')."_URL",
"Check table `".request()->input('table', 'unknown')."` exists.",
],
];
},
],
Integration with Custom Errors:
ErrorSolutions facade to handle custom exceptions:
use Spatie\ErrorSolutions\Facades\ErrorSolutions;
// In an Exception Handler:
public function render($request, Throwable $exception) {
if ($exception instanceof CustomException) {
return ErrorSolutions::render($request, $exception, [
'title' => 'Custom Error',
'solutions' => ['Solution 1', 'Solution 2'],
]);
}
}
Conditional Solutions:
when() in config to show solutions based on environment or context:
'solutions' => [
'RuntimeException' => [
'solutions' => [
'Check your logs.' => ['env' => 'local'],
'Contact support.' => ['env' => 'production'],
],
],
],
Localization:
'solutions' => [
'Symfony\Component\HttpKernel\Exception\NotFoundHttpException' => [
'title' => __('error-solutions::not-found.title'),
'solutions' => [
__('error-solutions::not-found.solution-1'),
],
],
],
php artisan vendor:publish --tag=laravel-error-solutions-lang
API Error Responses:
ErrorSolutions::toArray() method to include solutions in API error responses:
return response()->json([
'error' => 'Validation failed',
'solutions' => ErrorSolutions::toArray($exception),
], 422);
Logging Solutions:
App\Exceptions\Handler:
public function report(Throwable $exception) {
\Log::error($exception->getMessage(), [
'solutions' => ErrorSolutions::toArray($exception),
]);
}
Dynamic Solution Generation:
class DynamicSolutionGenerator {
public function generate(Throwable $exception): array {
return [
'title' => 'Dynamic Solution',
'solutions' => [
"Check the variable `\$exception->getTrace()[0]['args'][0]`",
],
];
}
}
ErrorSolutionsServiceProvider:
$this->app->singleton(DynamicSolutionGenerator::class);
Testing:
$exception = new \RuntimeException();
$solutions = ErrorSolutions::getSolutions($exception);
$this->assertContains('Test solution', $solutions);
Config Overrides:
solutions.php override default ones. Use + to merge:
'solutions' => [
'+' => [
'Symfony\Component\Debug\Exception\FatalErrorException' => [
'solutions' => ['Add this to existing solutions.'],
],
],
],
Performance:
'solutions' => [
'RuntimeException' => function () {
return Cache::remember('solutions.runtime', 60, function () {
return ['Cached solution'];
});
},
],
Exception Matching:
getPrevious() for wrapped exceptions:
'solutions' => [
'Illuminate\Database\QueryException' => [
'solutions' => [
'Check the underlying exception: '.($exception->getPrevious()?->getMessage() ?? 'None'),
],
],
],
Blade Template Caching:
php artisan view:clear
Environment-Specific Solutions:
solutions.php are merged across environments. Use env() checks in closures:
'solutions' => [
'RuntimeException' => function () {
return ['env' => app()->environment('local') ? 'Debug locally' : 'Deploy fix'];
},
],
Inspect Solutions:
use Spatie\ErrorSolutions\Facades\ErrorSolutions;
dd(ErrorSolutions::getSolutions(new \RuntimeException()));
Disable Solutions:
config/error-solutions.php:
'enabled' => env('APP_DEBUG') === false,
Log Unhandled Exceptions:
public function handle($request, Closure $next) {
try {
return $next($request);
} catch (Throwable $e) {
\Log::error('Unhandled error', [
'solutions' => ErrorSolutions::toArray($e),
]);
throw $e;
}
}
Custom Error Pages:
php artisan vendor:publish --tag=laravel-error-solutions-views
resources/views/vendor/error-solutions/errors/500.blade.php.Custom Solution Providers:
ErrorSolutionsServiceProvider:
$this->app->make(\Spatie\ErrorSolutions\ErrorSolutions::class)
->addSolutionProvider(new class {
public function getSolutions(): array {
return [
'App\Exceptions\CustomException' => [
'title' => 'Custom Error',
'solutions' => ['Custom solution.'],
],
];
}
});
Solution Events:
error-solutions::solutions-generated):
Event::listen('error-solutions::solutions-generated', function ($solutions, $exception) {
// Log or modify solutions dynamically
});
Solution API:
ErrorSolutions class to add methods:
namespace Spatie\ErrorSolutions;
class ErrorSolutions extends \Spatie\ErrorSolutions\ErrorSolutions {
public function getSolutionCount(Throwable $exception): int {
return count($this->getSolutions($exception));
}
}
Database-Backed Solutions:
'solutions' => [
'RuntimeException' => function () {
return Solution::where('exception', 'RuntimeException')->first()->solutions;
},
],
How can I help you explore Laravel packages today?