PHPackages                             hosmelq/fault-php - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Debugging &amp; Profiling](/categories/debugging)
4. /
5. hosmelq/fault-php

ActiveLibrary[Debugging &amp; Profiling](/categories/debugging)

hosmelq/fault-php
=================

Composable helpers for wrapping and aggregating PHP exceptions with codes, context, origins, and clear internal and user messages.

04PHP

Since Sep 21Pushed 9mo agoCompare

[ Source](https://github.com/hosmelq/fault-php)[ Packagist](https://packagist.org/packages/hosmelq/fault-php)[ RSS](/packages/hosmelq-fault-php/feed)WikiDiscussions main Synced today

READMEChangelogDependenciesVersions (1)Used By (0)

Fault PHP
=========

[](#fault-php)

Composable helpers for wrapping and aggregating PHP exceptions with codes, context, origins, and clear internal and user messages.

Introduction
------------

[](#introduction)

Wrap errors with rich, structured metadata and traverse entire exception chains ergonomically. Attach user‑facing and internal messages, codes, call‑site origins, and context, then extract them consistently for logging and display.

```
use Throwable;
use HosmelQ\Fault\Fault;
use HosmelQ\Fault\Wrap;

try {
    // Some operation that can fail
} catch (Throwable $error) {
    // Wrap with user + internal messages, a code, and context
    $fault = Fault::wrap(
        $error,
        Wrap::code('err:stripe:payment:insufficient_funds'),
        Wrap::internal('Stripe API returned 402: insufficient_funds'),
        Wrap::public('Your payment could not be processed. Please try again later.'),
        Wrap::context(['customer_id' => 'cust_123', 'payment_method' => 'card_456']),
        Wrap::origin(),
    );

    throw $fault;  // Re‑throw enriched error
}

// Somewhere higher in the stack
try {
    // Application entrypoint, controller action, etc.
} catch (Throwable $error) {
    // Aggregate data across the whole chain
    $message = Fault::userMessage($error);  // "Your payment could not be processed. Please try again later."
    $code = Fault::code($error);            // "err:stripe:payment:insufficient_funds"
    $ctx = Fault::context($error);          // ['customer_id' => 'cust_123', 'payment_method' => 'card_456']
    $intern = Fault::internals($error);     // ["Stripe API returned 402: insufficient_funds", "... base error ..."]
    $origins = Fault::origins($error);      // [[file => '...', line => 123], ...]
}
```

It produces a standard `FaultException` layer you can re‑throw and later traverse to extract codes, messages, context, and origins across nested exceptions.

Requirements
------------

[](#requirements)

- PHP 8.4+

Installation &amp; setup
------------------------

[](#installation--setup)

Install the package via composer:

```
composer require hosmelq/fault-php
```

Basic usage
-----------

[](#basic-usage)

### Getting started

[](#getting-started)

Create a new fault with an internal message and attach wrappers for public text, codes, and context:

```
use HosmelQ\Fault\Fault;
use HosmelQ\Fault\Wrap;

$fault = Fault::new(
    'Email validation failed',  // internal message (developer‑facing)
    Wrap::public('Please check your email address.'),
    Wrap::code('err:validation:email:invalid_format'),
    Wrap::context(['field' => 'email', 'value' => 'invalid@']),
);

// Extract values across the chain
Fault::userMessage($fault);  // "Please check your email address."
Fault::internals($fault);    // ["Email validation failed"]
Fault::code($fault);         // "err:validation:email:invalid_format"
Fault::context($fault);      // ['field' => 'email', 'value' => 'invalid@']
```

### Wrapping existing throwables

[](#wrapping-existing-throwables)

Wrap any existing `Throwable` to add fault metadata without losing the original exception:

```
use Throwable;
use HosmelQ\Fault\Fault;
use HosmelQ\Fault\Wrap;

try {
    // Code that might throw
} catch (Throwable $error) {
    $fault = Fault::wrap(
        $error,
        Wrap::public('Failed to send email. Please verify the recipient address.'),
        Wrap::internal('SMTP server rejected message delivery'),
        Wrap::code('err:resend:email:smtp_failure'),
    );

    throw $fault;
}
```

### Aggregating multiple errors

[](#aggregating-multiple-errors)

Combine multiple throwables into a single fault envelope for batch operations:

```
use HosmelQ\Fault\Fault;
use HosmelQ\Fault\Wrap;

$errors = [$mysqlError, $redisError, $resendError];

$combined = Fault::combine(
    $errors,
    Wrap::public('Multiple service failures occurred. Please try again later.')
);

// The previous exception is an AggregateFault with the original errors
$prev = $combined->getPrevious();

// User‑facing message is taken from the newest layers first
Fault::publicMessages($combined);  // ['Multiple service failures occurred. Please try again later.']
```

### Merging context newest‑first

[](#merging-context-newestfirst)

Merge context newest‑first. Newer layer values override older ones:

```
$root = Fault::new(
    'Payment processing failed',
    Wrap::context(['env' => 'prod', 'customer_id' => 'cust_123'])
);
$wrap = Fault::wrap(
    $root,
    Wrap::context(['customer_id' => 'cust_456', 'payment_method' => 'card_789'])
);
$merged = Fault::context($wrap);

// ['customer_id' => 'cust_456', 'payment_method' => 'card_789', 'env' => 'prod']
```

### Capturing origins

[](#capturing-origins)

Capture the file and line where a layer is added, then collect unique origins across the chain:

```
use HosmelQ\Fault\Fault;
use HosmelQ\Fault\Wrap;

$base = Fault::new('Database connection failed');
$a = Fault::wrap($base, Wrap::origin());  // captures this call site
$b = Fault::wrap($a, Wrap::origin());

$origins = Fault::origins($b);
// [ ['file' => '/path/To/File.php', 'line' => 123], ... ]
```

### Using enums

[](#using-enums)

Enums are accepted anywhere a message or code is expected. Backed enums use `value`, and unit enums use `name`:

```
use HosmelQ\Fault\Wrap;

enum ErrorCode: int
{
    case NotFound = 404;
}

enum Notice: string
{
    case Failure = 'failure';
}

enum Level
{
    case Warning;
}

Wrap::code(ErrorCode::NotFound);

Wrap::internal(Notice::Failure);

Wrap::public(Level::Warning);
```

Testing
-------

[](#testing)

```
composer test
```

Changelog
---------

[](#changelog)

Please see [CHANGELOG.md](CHANGELOG.md) for more information on what has changed recently.

Credits
-------

[](#credits)

- [Hosmel Quintana](https://github.com/hosmelq)
- [All Contributors](../../contributors)

**Based on:**

- [fault](https://github.com/Southclaws/fault)

License
-------

[](#license)

The MIT License (MIT). Please see [License File](LICENSE.md) for more information.

###  Health Score

16

—

LowBetter than 4% of packages

Maintenance41

Moderate activity, may be stable

Popularity3

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity14

Early-stage or recently created project

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

### Community

Maintainers

![](https://www.gravatar.com/avatar/97fd048037c6d5ccfeebf11961838d5db2dca1baca14fefa373230b301389a03?d=identicon)[hosmelq](/maintainers/hosmelq)

---

Top Contributors

[![hosmelq](https://avatars.githubusercontent.com/u/1166143?v=4)](https://github.com/hosmelq "hosmelq (1 commits)")

---

Tags

aggregationcontexterror-handlingexceptionfaultwrapping

### Embed Badge

![Health badge](/badges/hosmelq-fault-php/health.svg)

```
[![Health](https://phpackages.com/badges/hosmelq-fault-php/health.svg)](https://phpackages.com/packages/hosmelq-fault-php)
```

###  Alternatives

[fjogeleit/prometheus-messenger-middleware

Prometheus Middleware for the Symfony Messenger Component

2255.2k](/packages/fjogeleit-prometheus-messenger-middleware)[spatie/craft-ray

Easily debug CraftCMS projects

1638.6k](/packages/spatie-craft-ray)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
