Exceptions
Credits throws two exceptions of its own under a common base, passes a handful of money-for-laravel exceptions through unwrapped, throws package-toolkit’s InvalidConfigurationException on a malformed setting, and lets Laravel’s DeadlockException reach you inside your own transactions:
| Exception | Thrown when |
|---|---|
CreditsException | Base class (a RuntimeException) of InsufficientCreditsException and BucketNotDenominatedException — catch it to handle any credits failure. |
InsufficientCreditsException | A deduction would take a bucket below minimum_balance while overdraft is disallowed. Carries $creditable, $requested (signed) and $available; message from credits::messages.insufficient. |
BucketNotDenominatedException | A money-typed call — the scope’s money(), addMoney(), deductMoney(), modifyMoney() or formatMoney(), or the trait’s creditsBalanceMoney(), modifyCreditsMoney() or formatCreditsBalance() — on a bucket not listed in credits.currencies. Carries $bucket (the resolved name); message from credits::messages.not_denominated. |
InvalidArgumentException | add() or deduct() (or addMoney() / deductMoney()) received a negative amount — use modify() for a signed change. |
CurrencyMismatch | From money: modifyCreditsMoney() received a Money in another currency (code + exponent). |
AmountOverflow | From money: a Money amount does not fit the signed 64-bit ledger column. |
UnknownCurrency | From money: credits.currencies maps a bucket to a code the registry does not know. |
InvalidMoneyConfiguration | From money: credits.currencies is malformed, or credits.rounding names no rounding mode. |
InvalidAmount | From money: a display scale beyond 36 decimal places. |
InvalidConfigurationException | From package-toolkit: a config value is malformed — a model that is not Credit or a subclass, an unknown key_type or primary_key_type, a non-boolean allow_overdraft, a non-integer minimum_balance, a non-string default_bucket, a scale outside 0–36, or a non-callable modifiable entry. The message names the key. |
DeadlockException | From Laravel: inside your own DB::transaction() on Postgres REPEATABLE READ or SERIALIZABLE, a racing change of the same owner (SQLSTATE 40001). Nothing is written — retry the whole transaction. |
Handling them
Catch the specific cases you can act on, then fall back to the base class:
use RoundlyConsulting\Credits\Exceptions\CreditsException;
use RoundlyConsulting\Credits\Facades\Credits;
use RoundlyConsulting\Credits\Exceptions\InsufficientCreditsException;
use RoundlyConsulting\Money\Exceptions\AmountOverflow;
use RoundlyConsulting\Money\Exceptions\CurrencyMismatch;
try {
Credits::for($user)->bucket('store_credit')->modifyMoney($amount, 'checkout');
} catch (InsufficientCreditsException $e) {
// not enough in the bucket: $e->requested, $e->available, $e->creditable
} catch (CurrencyMismatch | AmountOverflow $e) {
// wrong currency, or beyond the 64-bit ledger — nothing was written
} catch (CreditsException $e) {
// any other credits failure, e.g. BucketNotDenominatedException ($e->bucket)
}A refused change never leaves a partial write: the overdraft guard runs inside the write’s transaction, and the money checks run before it starts.
Show your open-source love
This package is free and MIT-licensed. If it saves you time, a one-off donation or a Patreon membership keeps it maintained, tested and documented.
More ways to support, including cryptoBy donating, you agree to our donation terms.
Want this built into your product?
We integrate our packages into custom Laravel and AI builds. Tell us what you're working on and we'll reply within 48 hours.