Skip to content

Handling Errors ​

Everything in the package throws a single exception type, RaastQrException, carrying a machine-readable code.

php
use RealRashid\RaastQr\Exceptions\RaastQrException;
use RealRashid\RaastQr\Facades\RaastQr;

try {
    $qr = RaastQr::iban($request->iban)->amount($request->amount)->toSvg();
} catch (RaastQrException $e) {
    return response()->json([
        'code' => $e->reason(),      // 'INVALID_AMOUNT'
        'message' => $e->getMessage(),
    ], 422);
}

The Codes ​

CodeCause
INVALID_OPTIONSNo IBAN was supplied and none is configured
INVALID_IBANWrong shape, wrong country, or failed checksum
INVALID_AMOUNTNot positive, too many decimals, or too long
INVALID_EXPIRYNot a real calendar date, or the wrong format
INVALID_CRC_INPUTInternal — the checksum received a non-string
INVALID_QR_OPTIONSBad colour, bad format, bad error correction, missing logo
RENDERER_FAILUREThe image layer could not draw the code

Branching on the Enum ​

$e->reason() gives you the string. $e->errorCode gives you the enum, which is what you want in a match:

php
use RealRashid\RaastQr\Enums\ErrorCode;

try {
    return RaastQr::iban($vendor->iban)->amount($order->total)->format('svg');
} catch (RaastQrException $e) {
    return match ($e->errorCode) {
        ErrorCode::InvalidIban => back()->withErrors([
            'iban' => 'This vendor\'s account number needs updating.',
        ]),
        ErrorCode::InvalidAmount => back()->withErrors([
            'amount' => 'This total cannot be encoded in a QR code.',
        ]),
        default => throw $e,
    };
}

Note the default => throw $e

Rethrowing anything you didn't plan for keeps genuine bugs visible instead of swallowing them into a generic 422.

$code vs $errorCode ​

RaastQrException extends InvalidArgumentException, so it inherits $code from PHP's Exception — an integer, always 0 here. The enum lives on its own property:

php
$e->code;        // 0, inherited from \Exception — ignore it
$e->errorCode;   // ErrorCode::InvalidAmount
$e->reason();    // 'INVALID_AMOUNT'

Catch Early, Not Late ​

The exception is thrown when you ask for output, not when you set a value:

php
$qr = RaastQr::iban('nonsense')->amount('also nonsense');   // fine, nothing computed
$qr->toPng();                                               // throws here

That means a builder returned from a controller throws during response rendering, which is a worse place to handle it. If the input came from a user, validate first:

php
$request->validate([
    'iban' => ['required', new PakistaniIban],
    'amount' => ['required', 'numeric', 'min:0.01', 'max:9999999.99', 'decimal:0,2'],
]);

See Validating IBANs.

Reporting ​

RaastQrException extends InvalidArgumentException, so Laravel reports it like any other exception. If bad IBANs are routine user input rather than bugs, tell the handler not to bother:

php
// bootstrap/app.php
->withExceptions(function (Exceptions $exceptions) {
    $exceptions->dontReport(RaastQrException::class);
})

Only do this once you're validating input properly, or you'll lose sight of real failures.


Made with ❤️ from Pakistan