Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Laravel Faulty Laravel Package

kamranahmedse/laravel-faulty

Laravel Faulty wraps fragile code in a fault-tolerant helper so exceptions don't break your app. Define fallbacks, like cached values, defaults, or closures, and Faulty returns them when the wrapped call fails, keeping API or service outages from taking down your requests.

View on GitHub
Deep Wiki
Context7

Getting Started

1. Install and register.

composer require kamranahmedse/laravel-faulty

On Laravel 5.4 and below, add the provider to config/app.php:

'providers' => [
    // ...
    KamranAhmed\Faulty\FaultyServiceProvider::class,
],

On 5.5+ auto-discovery picks it up, but verify it actually resolves — this package predates discovery conventions and later Laravel versions.

2. Publish the config and read it before writing any code.

php artisan vendor:publish --provider="KamranAhmed\Faulty\FaultyServiceProvider"

The published config/faulty.php is the real contract: it holds the exception→status mapping and the handler class that replaces Laravel's default Illuminate\Foundation\Exceptions\Handler. Read the handler class too (usually a few dozen lines under src/) — you will be subclassing or copying it.

3. Smoke-test the first use case. The whole point is that a thrown exception becomes an RFC 7807 response instead of HTML or a generic {"message": "..."}:

Route::get('/api/users/{user}', function ($user) {
    return App\User::findOrFail($user);
});
curl -i -H "Accept: application/json" http://localhost/api/users/999
HTTP/1.1 404 Not Found
Content-Type: application/problem+json

{
  "type": "about:blank",
  "title": "Not Found",
  "status": 404,
  "detail": "No query results for model [App\\User] 999"
}

If you see application/problem+json and a status member, the handler swap worked. If you still get HTML or Laravel's default JSON envelope, the provider or handler binding is wrong — that is your first thing to debug.

4. Where to look first, in order: the published config → the package's handler class → your App\Exceptions\Handler (to confirm what it now extends).

Implementation Patterns

Scope it to the API surface. The package converts every uncaught exception, which is wrong for a mixed web/API app — your Blade 404 and 500 pages will start returning JSON. Two workable patterns:

  • Register the provider only for API routes (separate app bootstrap, or an API-specific service provider).
  • Keep one handler but branch on $request->expectsJson() || $request->is('api/*') inside your handler's render(), delegating to the parent for HTML requests.

I'd take the second — it's a five-line guard and keeps local debugging sane.

Map domain exceptions to status codes in config. This is the highest-leverage usage: business errors become first-class HTTP semantics.

// config/faulty.php (shape is indicative — verify against your published version)
'status' => [
    Illuminate\Database\Eloquent\ModelNotFoundException::class => 404,
    Illuminate\Validation\ValidationException::class          => 422,
    Illuminate\Auth\AuthenticationException::class            => 401,
    Illuminate\Auth\Access\AuthorizationException::class      => 403,
    App\Exceptions\InsufficientFundsException::class          => 402,
    App\Exceptions\RateLimitedException::class                => 429,
],

Anything unmapped should fall back to 500. Confirm the fallback explicitly rather than assuming it.

Give your exceptions the data the spec needs. Define a small contract (the package ships one, or roll your own) exposing getStatusCode(), getTitle(), and optional extension members, then throw it instead of building responses by hand:

class InsufficientFundsException extends RuntimeException
{
    public function __construct(private float $shortfall) {}

    public function getStatusCode(): int { return 402; }
    public function getTitle(): string  { return 'Insufficient Funds'; }
    public function getDetails(): array { return ['shortfall' => $this->shortfall]; }
}

The caller just throws; the handler produces type/title/status/detail plus shortfall. This is the pattern that scales — controllers never touch error payloads.

Populate instance with something traceable. The spec's instance field is the natural home for the request path or a request ID from middleware. Add it once in the handler so every error response correlates with logs.

Handle validation and auth deliberately. Laravel throws ValidationException (with an errors bag) and AuthenticationException on its own. These may render through a different path than your custom exceptions — test them individually. If you want the RFC-style errors extension member, you will likely override render() for that case.

Assert the contract in tests. Since this is an API-wide change, lock it down:

$this->getJson('/api/users/999')
     ->assertStatus(404)
     ->assertJsonPath('status', 404)
     ->assertJsonStructure(['type', 'title', 'status', 'detail']);

$this->assertStringContainsString(
    'application/problem+json',
    $this->get('/api/users/999')->headers->get('Content-Type')
);

Document it in OpenAPI. Declaring application/problem+json as the error media type for every operation is the payoff of adopting the spec — otherwise clients keep branching on 200-only shapes.

Gotchas and Tips

This package is stale — budget for a fork. Last release February 2017; Laravel 5.x / PHP 7.0 era. Illuminate\Foundation\Exceptions\Handler has changed signature (render($request, Throwable) in modern versions, plus registerErrorViewPaths, renderable/reportable registration). On Laravel 8+ expect to either patch the base handler or vendor the logic. The code is small — copying ~100 lines into App\Exceptions\Handler is often cheaper and safer than fighting compatibility.

Modern Laravel does this natively. In Laravel 8+ you can skip the dependency entirely:

// bootstrap/app.php  (Laravel 11) or App\Exceptions\Handler
->withExceptions(function (Exceptions $exceptions) {
    $exceptions->render(function (Throwable $e, Request $request) {
        if (! $request->expectsJson()) return null;
        return response()->json([...], $status, ['Content-Type' => 'application/problem+json']);
    });
});

Assess the package as a reference implementation of the spec rather than a long-term dependency.

APP_DEBUG=true may stop mattering. When the handler is swapped, you can lose Ignition/Whoops stack traces locally while gaining spec-shaped errors. Add a debug guard that renders the normal trace page when config('app.debug') is true and the request is from a local environment — otherwise your local dev experience degrades noticeably.

detail is $e->getMessage(). That means raw exception messages — including SQL fragments and file paths from PDO exceptions — can reach clients. Sanitize before shipping: whitelist your own exception messages and replace everything else with a generic string on 5xx.

Don't break existing frontend error handling. Laravel's default validation response is {"message": ..., "errors": {...}}. If you adopt a spec-shaped 422, every client parsing message breaks. Either preserve message as an extension member during migration or version the API.

Config caching bites. php artisan config:cache will freeze your mapping; clear it (php artisan config:clear) after edits and before debugging "why isn't my mapping applied."

4xx noise in logs. Laravel's report() still fires for exceptions that now render as 400-level responses. Add dontReport entries for expected domain exceptions or your logs (and Sentry bill) will be dominated by validation and 404s.

Test the content type loosely. Many responses append ; charset=UTF-8; an exact assertHeader('Content-Type', 'application/problem+json') will fail. Use str_contains on the header value.

The extension point is the handler class. Everything routes through one class — subclass it, keep the problem+json serialization, and override render()/toProblem() for your cases. Don't scatter response-building across middleware or controllers; that's exactly what this package exists to prevent.

Watch the edges the handler misses. Exceptions thrown before the app's exception handler is reachable (early middleware, Handler bootstrapping failures) and framework-generated responses like 419 CSRF and 429 throttling may not flow through the package. Test those explicitly if clients depend on the shape.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
gmostafa/php-graphql-client
xeviant/paystack
snowsoft/faker
meditationsteps/blogetc
animalyoung/laravel-influxdb
onix-solutions/sms-telera
lonely-lights/prosetta
oxygen/data
oxygen/core
jengo/base
xiloryx/log-collector
a21ns1g4ts/filament-stripe
la-php/laravel-admin
artisan-build/community-prompts
vleroy/smart
ayles-software/laravel-australian-public-holidays
cboxdk/laravel-id-spatie
cboxdk/laravel-id-billing
cboxdk/laravel-id-billing-bridge
simple-as-fuck/php-performance-log