phacility/phabricator · error · Exception
Unable to refund some charges!
Error message
Unable to refund some charges!
What it means
After iterating all refundable charges (each attempt can fail inside the provider, leaving $refunded false for that charge), any remaining positive refund amount triggers 'Unable to refund some charges!'. It is an aggregate partial-failure signal: the requested refund could not be covered by the charges available, because at least one refund was rejected or had insufficient refundable balance.
Source
Thrown at src/applications/phortune/controller/cart/PhortuneCartCancelController.php:152
$provider->refundCharge($charge, $refund_charge);
$refunded = true;
} catch (Exception $ex) {
phlog($ex);
$cart->didFailRefund($charge, $refund_charge);
}
if ($refunded) {
$cart->didRefundCharge($charge, $refund_charge);
$refund = $refund->subtract($refund_amount);
}
if (!$refund->isPositive()) {
break;
}
}
if ($refund->isPositive()) {
throw new Exception(pht('Unable to refund some charges!'));
}
// TODO: If every HOLD and CHARGING transaction has been fully refunded
// and we're in a HOLD, REVIEW, PURCHASING or CHARGED cart state we
// probably need to kick the cart back to READY here (or maybe kill
// it if it was in REVIEW)?
return id(new AphrontRedirectResponse())->setURI($cancel_uri);
}
}
if ($is_refund) {
$title = pht('Refund Order?');
$body = pht('Really refund this order?');
$button = pht('Refund Order');
$cancel_text = pht('Cancel');
$form = id(new AphrontFormView())View on GitHub (pinned to 5720a38cfe)
Solutions
- Reconcile each charge's refund state in Phortune against the gateway's transaction history
- Fix the underlying provider failure (credentials, connectivity) and retry the cancel/refund
- Complete any remainder as a gateway-side refund and record it manually so balances match
Defensive patterns
Strategy: try-catch
Validate before calling
// Pre-check that total refundable balance covers the requested refund
$refundable_total = 0;
foreach ($charges as $charge) {
if (!$charge->isRefund()) {
$refundable_total += $charge->getAmountRefundable()->getValue();
}
}
if ($refundable_total < $refund->getValue()) {
throw new Exception('Insufficient refundable balance to cover the refund.');
} Try / catch
try {
// cancel + refund flow
} catch (Exception $ex) {
if (strpos($ex->getMessage(), 'Unable to refund some charges') !== false) {
// re-render the cart/charge table so operators see which charges remain unrefunded
}
} Prevention
- Reconcile Phortune charge balances with gateway history before refunding
- Never refund externally in the gateway dashboard without recording it in Phortune
- Monitor provider health and credentials so refund calls do not fail mid-flow
When it happens
Trigger: A provider API rejects one refund (insufficient funds at the gateway, auth failure, outage); part of the money was already refunded externally in the gateway dashboard; requesting a refund larger than what the un-refunded charge balances cover.
Common situations: Partial manual refunds done outside Phortune desynchronizing balances; transient gateway outages mid-cancel; charge-hold corner cases during double-clicks.
Related errors
- Unable to load provider for charge!
- Charge has no transaction ID!
- Unable to refund charge; no Stripe chargeID!
- Trying to refund non-positive amount of money!
- Trying to refund more money than remaining on charge!
AI-assisted analysis of phacility/phabricator@5720a38cfe (2026-08-21).
Data as JSON: /api/errors/896837b3dfc5bdc8.
Report an issue: GitHub.