Handling errors | laravel-mobile-pass | Spatie

 SPATIE

  Laravel Mobile Pass
======================

spatie.be/open-source

  [Docs](https://spatie.be/docs)  [Laravel-mobile-pass](https://spatie.be/docs/laravel-mobile-pass/v1)  Advanced-usage  Handling errors

 Version   v1

 Other versions for crawler [v1](https://spatie.be/docs/laravel-mobile-pass/v1)

  Handling errors
- [ Introduction ](https://spatie.be/docs/laravel-mobile-pass/v1/introduction)
- [ Support us ](https://spatie.be/docs/laravel-mobile-pass/v1/support-us)
- [ Requirements ](https://spatie.be/docs/laravel-mobile-pass/v1/requirements)
- [ Installation &amp; setup ](https://spatie.be/docs/laravel-mobile-pass/v1/installation-setup)
- [ Getting credentials from Apple ](https://spatie.be/docs/laravel-mobile-pass/v1/getting-credentials-from-apple)
- [ Getting credentials from Google ](https://spatie.be/docs/laravel-mobile-pass/v1/getting-credentials-from-google)
- [ Questions and issues ](https://spatie.be/docs/laravel-mobile-pass/v1/questions-issues)
- [ Changelog ](https://spatie.be/docs/laravel-mobile-pass/v1/changelog)
- [ About us ](https://spatie.be/docs/laravel-mobile-pass/v1/about-us)

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

- [ Generating your first pass ](https://spatie.be/docs/laravel-mobile-pass/v1/basic-usage/generating-your-first-pass)
- [ Delivering passes to users ](https://spatie.be/docs/laravel-mobile-pass/v1/basic-usage/handing-out-passes)
- [ Adding images ](https://spatie.be/docs/laravel-mobile-pass/v1/basic-usage/adding-images)
- [ Adding barcodes ](https://spatie.be/docs/laravel-mobile-pass/v1/basic-usage/adding-barcodes)
- [ Updating a pass ](https://spatie.be/docs/laravel-mobile-pass/v1/basic-usage/updating-a-pass)
- [ Retrieving mobile passes ](https://spatie.be/docs/laravel-mobile-pass/v1/basic-usage/retrieving-mobile-passes)
- [ Expiring passes ](https://spatie.be/docs/laravel-mobile-pass/v1/basic-usage/expiring-passes)

Available pass types
--------------------

- [ Introduction ](https://spatie.be/docs/laravel-mobile-pass/v1/available-pass-types/introduction)
- [ Boarding pass ](https://spatie.be/docs/laravel-mobile-pass/v1/available-pass-types/boarding-pass)
- [ Event ticket ](https://spatie.be/docs/laravel-mobile-pass/v1/available-pass-types/event-ticket)
- [ Coupon ](https://spatie.be/docs/laravel-mobile-pass/v1/available-pass-types/coupon)
- [ Loyalty card ](https://spatie.be/docs/laravel-mobile-pass/v1/available-pass-types/loyalty)
- [ Generic ](https://spatie.be/docs/laravel-mobile-pass/v1/available-pass-types/generic)

Apple Wallet
------------

- [ Field zones ](https://spatie.be/docs/laravel-mobile-pass/v1/apple-wallet/field-zones)
- [ Apple-specific methods ](https://spatie.be/docs/laravel-mobile-pass/v1/apple-wallet/apple-specific-methods)
- [ Pass relevance ](https://spatie.be/docs/laravel-mobile-pass/v1/apple-wallet/pass-relevance)
- [ NFC passes ](https://spatie.be/docs/laravel-mobile-pass/v1/apple-wallet/nfc)
- [ Attaching Wi-Fi credentials ](https://spatie.be/docs/laravel-mobile-pass/v1/apple-wallet/attaching-wifi-credentials)
- [ Storing mobile passes ](https://spatie.be/docs/laravel-mobile-pass/v1/apple-wallet/storing-mobile-passes)

Google Wallet
-------------

- [ Pass classes ](https://spatie.be/docs/laravel-mobile-pass/v1/google-wallet/pass-classes)
- [ Object methods ](https://spatie.be/docs/laravel-mobile-pass/v1/google-wallet/object-methods)
- [ Hosting pass images ](https://spatie.be/docs/laravel-mobile-pass/v1/google-wallet/hosting-images)

Advanced usage
--------------

- [ Handling errors ](https://spatie.be/docs/laravel-mobile-pass/v1/advanced-usage/handling-errors)
- [ Customizing actions ](https://spatie.be/docs/laravel-mobile-pass/v1/advanced-usage/customizing-actions)
- [ Customizing models ](https://spatie.be/docs/laravel-mobile-pass/v1/advanced-usage/customizing-models)
- [ Reading stored passes ](https://spatie.be/docs/laravel-mobile-pass/v1/advanced-usage/reading-stored-passes)
- [ Events ](https://spatie.be/docs/laravel-mobile-pass/v1/advanced-usage/events)
- [ Testing your passes ](https://spatie.be/docs/laravel-mobile-pass/v1/advanced-usage/testing-your-passes)

 Handling errors
===============

###  On this page

1. [ Validation errors ](#content-validation-errors)
2. [ Configuration errors ](#content-configuration-errors)
3. [ Platform mismatches ](#content-platform-mismatches)
4. [ Download errors ](#content-download-errors)
5. [ Google Wallet request failures ](#content-google-wallet-request-failures)
6. [ Apple Wallet request failures ](#content-apple-wallet-request-failures)
7. [ Certificate signing failures ](#content-certificate-signing-failures)
8. [ Missing image files ](#content-missing-image-files)

The package throws a handful of typed exceptions so you can recover from the common failure modes without parsing error messages.

Every package-specific exception implements the `Spatie\LaravelMobilePass\Exceptions\MobilePassException` marker interface, so you can catch anything this package threw with a single catch clause if that's all you care about:

```
use Spatie\LaravelMobilePass\Exceptions\MobilePassException;

try {
    // something that touches the package
} catch (MobilePassException $exception) {
    report($exception);
}
```

Each exception class below also implements this interface; the sections that follow describe when each specific one fires.

Validation errors
-----------------------------------------------------------------------------------------------------------

Every builder runs a Laravel validator before it hands a pass off to Apple or Google. If a required field is missing, or a value has the wrong shape, `save()` throws a `Spatie\LaravelMobilePass\Exceptions\InvalidPass`.

```
use Spatie\LaravelMobilePass\Exceptions\InvalidPass;

try {
    EventTicketPassBuilder::make()
        ->setOrganizationName('Fab Four Promotions')
        // setSerialNumber omitted
        ->setDescription('The Beatles at Shea Stadium')
        ->save();
} catch (InvalidPass $exception) {
    report($exception);
}
```

`InvalidPass` extends Laravel's `Illuminate\Validation\ValidationException`, so a couple of things still work out of the box:

- `$exception->errors()` gives you the field-by-field reasons.
- Catching `ValidationException` instead of `InvalidPass` still works, if you prefer the broader type.
- Thrown from a controller method, Laravel's default exception handler still renders a 422 JSON response with the errors.

Configuration errors
--------------------------------------------------------------------------------------------------------------------

`Spatie\LaravelMobilePass\Exceptions\InvalidConfig` is thrown when the `mobile-pass` config file is missing something the package needs. The most common reasons:

- `InvalidConfig::missingGoogleCredentials()`: no Google service account key is configured. Set either `MOBILE_PASS_GOOGLE_KEY` (raw JSON or base64-encoded JSON) or `MOBILE_PASS_GOOGLE_KEY_PATH`.
- `InvalidConfig::webserviceHostMustBeHttps($host)`: `mobile-pass.apple.webservice.host` is set to a non-HTTPS URL. Apple rejects passes whose `webServiceURL` isn't HTTPS. Leave the value empty for local development over `http://`.
- `InvalidConfig::passBuilderNotRegistered()` and `InvalidConfig::invalidPassBuilderClass()`: a builder you're referencing isn't in the `builders` config key, or doesn't extend the expected base class.

These surface at runtime the first time the package tries to use the misconfigured value. Catch them in a `Handler::register()` call if you want to render a friendlier error page for developers.

Platform mismatches
-----------------------------------------------------------------------------------------------------------------

The `Spatie\LaravelMobilePass\Exceptions\PlatformDoesntSupport` exception fires when you call a method that doesn't make sense for the pass's platform.

Calling `$mobilePass->updateField(...)` on a Google pass throws `PlatformDoesntSupport::cannotUpdateFields(Platform::Google)`. Use the Google builder's `content`-patching flow instead (see [Updating a pass](basic-usage/updating-a-pass)).

It's the kind of mistake you want to catch during development. Let it bubble to your exception handler in production; it indicates a bug in your code, not a user error.

Download errors
-----------------------------------------------------------------------------------------------------

Calling `$mobilePass->download()` on a Google pass throws `Spatie\LaravelMobilePass\Exceptions\CannotDownload::wrongPlatform($mobilePass)`. The same exception fires if a Google pass is requested through Apple's download route. Google passes aren't files; they live on Google's servers and users reach them through a `pay.google.com` save URL.

Google Wallet request failures
--------------------------------------------------------------------------------------------------------------------------------------------------

Every call to Google's Wallet API (creating a Class, creating an Object, fetching or retiring) goes through a typed failure. The `Spatie\LaravelMobilePass\Exceptions\GoogleWalletRequestFailed` exception carries the original HTTP response so you can inspect what Google actually said:

```
use Spatie\LaravelMobilePass\Exceptions\GoogleWalletRequestFailed;

try {
    EventTicketPassClass::make('duplicate-id')
        ->setIssuerName('...')
        ->save();
} catch (GoogleWalletRequestFailed $exception) {
    logger()->error('Google Wallet rejected the request', [
        'status' => $exception->status,
        'body' => $exception->body,
        'endpoint' => $exception->endpoint,
    ]);
}
```

The common causes are duplicate Class IDs, malformed payloads, or an expired service account key. Google's error bodies are JSON; decode them to read the field-level reasons.

Apple Wallet request failures
-----------------------------------------------------------------------------------------------------------------------------------------------

The package notifies Apple Wallet of pass updates over APNs. If Apple responds with a non-2xx status (except 410, which signals a stale registration that the package cleans up automatically), the push action throws `Spatie\LaravelMobilePass\Exceptions\AppleWalletRequestFailed`. The exception has the same shape as its Google counterpart:

```
use Spatie\LaravelMobilePass\Exceptions\AppleWalletRequestFailed;

try {
    $mobilePass->updateField('seat', '13A');
} catch (AppleWalletRequestFailed $exception) {
    logger()->error('APNs push was rejected', [
        'status' => $exception->status,
        'body' => $exception->body,
        'endpoint' => $exception->endpoint,
    ]);
}
```

The common causes are an expired pass-type certificate, a wrong certificate password, or a revoked APNs token. Persistent rejections point at your `MOBILE_PASS_APPLE_CERTIFICATE_PATH` or `MOBILE_PASS_APPLE_CERTIFICATE_PASSWORD`.

If APNs itself can't be reached (DNS, network, TLS), Laravel's HTTP client raises a `Illuminate\Http\Client\ConnectionException`. The `PushPassUpdateJob` retries according to your queue's retry policy when dispatched to a queue; when running synchronously, the exception bubbles up on the web request that triggered the update.

Certificate signing failures
--------------------------------------------------------------------------------------------------------------------------------------------

`.pkpass` generation uses the underlying `pkpass/pkpass` library. When it can't load or use the pass-signing certificate (wrong path, wrong password, expired cert, bad PKCS12 format), the package catches the raw `PKPass\PKPassException` and re-throws it as `Spatie\LaravelMobilePass\Exceptions\InvalidCertificate`:

```
use Spatie\LaravelMobilePass\Exceptions\InvalidCertificate;

try {
    $mobilePass->generate();
} catch (InvalidCertificate $exception) {
    report($exception);
}
```

The exception's message names the env vars you should check (`MOBILE_PASS_APPLE_CERTIFICATE_PATH`, `MOBILE_PASS_APPLE_CERTIFICATE`, `MOBILE_PASS_APPLE_CERTIFICATE_PASSWORD`). The original `PKPassException` is available through `$exception->getPrevious()` if you need the raw OpenSSL detail.

Missing image files
-----------------------------------------------------------------------------------------------------------------

Apple builders read their images off disk. If you hand `setLogoImage()`, `setIconImage()`, and friends a path that doesn't exist, the builder throws `Spatie\LaravelMobilePass\Exceptions\ImageNotFound` immediately (not at `save()` time), so a typo surfaces right at the call site:

```
use Spatie\LaravelMobilePass\Exceptions\ImageNotFound;

try {
    $builder->setLogoImage('/no/such/file.png');
} catch (ImageNotFound $exception) {
    // $exception->getMessage() includes the missing path
}
```

Google's class builders take URLs, not paths, so this doesn't apply there; Google fetches the image itself when it renders the pass.

 A good
match?
-------------

### What we do best

- All things Laravel
- Custom frontend components
- Building APIs
- AI-powered features
- Simplifying things
- Clean solutions
- Integrating services

### Not our cup of tea

- WordPress themes
- Cutting corners
- Free mockups to win a job
- "Just execute the briefing"

 In short: we'd like to be a **substantial part** of your project.

 [ Get in touch via email ](mailto:info@spatie.be?subject=A%20good%20match%21&body=Tell%20us%20as%20much%20as%20you%20can%20about%0A-%20your%20online%20project%0A-%20your%20planning%0A-%20your%20budget%0A-%20%E2%80%A6%0A%0AAnything%20that%20helps%20us%20to%20start%20straightforward%21)
