Laravel Magazine
rescue(): One-Line Graceful Error Handling for Flaky Code Paths

rescue(): One-Line Graceful Error Handling for Flaky Code Paths

Eric Van Johnson ·

Every codebase has a few calls that are "probably fine but might not be": a third-party geocoding lookup, an optional analytics ping, a currency conversion API. When one of those fails, you usually don't want to blow up the whole request, you want to log it and move on with a sensible default. That's exactly what Laravel's rescue() helper is for.

The manual version

try {
    $rate = $exchangeRateApi->getRate('USD', 'EUR');
} catch (\Throwable $e) {
    report($e);
    $rate = 1.0;
}

Four lines, and you'll write some version of it a dozen times across a project.

With rescue()

$rate = rescue(
    fn () => $exchangeRateApi->getRate('USD', 'EUR'),
    rescue: 1.0
);

rescue() runs the closure, catches any Throwable, reports it through your normal exception handler (so it still shows up in Sentry, Flare, or the log driver you've configured), and returns the fallback value instead of letting the exception propagate.

The fallback can be a closure too

If computing the default itself is expensive or needs context, pass a closure instead of a static value:

$shippingEstimate = rescue(
    fn () => $carrierApi->estimate($order),
    rescue: fn () => ShippingEstimate::flatRateFallbackFor($order)
);

The fallback closure only runs if the primary one throws, so you're not paying for both code paths on the happy path.

Turning off reporting

Sometimes a failure is expected and noisy enough in your error tracker that you don't want it reported at all, just swallowed with a default:

$avatarUrl = rescue(
    fn () => $gravatarClient->urlFor($user->email),
    rescue: asset('images/default-avatar.png'),
    report: false
);

Where this pattern earns its keep

At PhpArchitect we use rescue() heavily around anything that talks to a third-party service where a failure shouldn't be a user-facing 500: shipping rate lookups, optional enrichment calls, non-critical webhooks fired on the way out of a request. It keeps the "happy path plus fallback" logic readable in one expression instead of a multi-line try/catch block that clutters up a controller or action class.

When not to use it

rescue() is for genuinely optional operations. If the failure means the request truly can't succeed, for example your payment charge call, let the exception propagate and handle it explicitly. Swallowing an exception on a critical path just to avoid a try/catch is how you end up debugging "why did this order get created with no payment" six months later with nothing in the logs to explain it.

Stay Updated

Subscribe to our newsletter

Get latest news, tutorials, community articles and podcast episodes delivered to your inbox.

Weekly articles
We send a new issue of the newsletter every week on Friday.
No spam
We'll never share your email address and you can opt out at any time.