phacility/phabricator · error · Exception
Unable to update charge; no Stripe chargeID!
Error message
Unable to update charge; no Stripe chargeID!
What it means
Exception thrown by PhortuneStripePaymentProvider::updateCharge() when asked to refresh a charge that has no 'stripe.chargeID' metadata. The update path is Stripe_Charge::retrieve($charge_id, ...) — with no stored ID there is nothing to retrieve. The metadata is only written at the end of a successful executeCharge(), so this indicates the charge never completed (or was not a Stripe charge).
Source
Thrown at src/applications/phortune/provider/PhortuneStripePaymentProvider.php:194
$stripe_charge = Stripe_Charge::retrieve($charge_id, $secret_key);
$stripe_refund = $stripe_charge->refunds->create($params);
$id = $stripe_refund->id;
if (!$id) {
throw new Exception(pht('Stripe refund call did not return an ID!'));
}
$charge->setMetadataValue('stripe.refundID', $id);
$charge->save();
}
public function updateCharge(PhortuneCharge $charge) {
$this->loadStripeAPILibraries();
$charge_id = $charge->getMetadataValue('stripe.chargeID');
if (!$charge_id) {
throw new Exception(
pht('Unable to update charge; no Stripe chargeID!'));
}
$secret_key = $this->getSecretKey();
$stripe_charge = Stripe_Charge::retrieve($charge_id, $secret_key);
// TODO: Deal with disputes / chargebacks / surprising refunds.
}
private function getPublishableKey() {
return $this
->getProviderConfig()
->getMetadataValue(self::STRIPE_PUBLISHABLE_KEY);
}
private function getSecretKey() {
return $thisView on GitHub (pinned to 5720a38cfe)
Solutions
- Skip charges without 'stripe.chargeID' — their original flow (or its failure) must finish first.
- Limit update polling to CHARGED/HOLD charges that carry Stripe metadata and belong to the Stripe provider.
- If a real Stripe charge exists (searchable by charge PHID in the description), restore the metadata before polling.
Example fix
// before
$provider->updateCharge($charge);
// after
$charge_id = $charge->getMetadataValue('stripe.chargeID');
if (!strlen((string)$charge_id)) {
// No Stripe reference on this charge; nothing to update.
return;
}
$provider->updateCharge($charge); Defensive patterns
Strategy: validation
Validate before calling
// Only update charges that carry a Stripe reference.
function stripe_charge_is_updatable(PhortuneCharge $charge) {
return strlen((string) $charge->getMetadataValue('stripe.chargeID')) > 0;
}
if (!stripe_charge_is_updatable($charge)) {
// No Stripe object to retrieve; leave the charge to its own flow.
continue;
}
$provider->updateCharge($charge); Type guard
function charge_has_stripe_charge_id(PhortuneCharge $charge) {
$id = $charge->getMetadataValue('stripe.chargeID');
return is_string($id) && strlen($id) > 0;
} Try / catch
try {
$provider->updateCharge($charge);
} catch (Exception $ex) {
// Missing chargeID means the charge never completed via Stripe:
// log and exclude from future polling instead of retrying.
phlog(pht('Cannot update charge %s: %s', $charge->getPHID(), $ex->getMessage()));
} Prevention
- Scope update workers to charges with provider metadata and matching provider.
- Treat absent 'stripe.chargeID' as 'not a completed Stripe charge' — skip, don't poll.
- Repair interrupted charge flows promptly so half-written charges don't enter the poll set.
When it happens
Trigger: A charge-status worker or admin tool calling updateCharge() on a charge in HOLD/FAIL status whose executeCharge() never reached the save; polling a charge created by a different provider through the Stripe provider; metadata missing after a crash between charge creation and persistence.
Common situations: Generic pollers that update every open charge regardless of provider; test fixtures with hand-built charges; scripts run against carts stuck mid-checkout after a Stripe outage.
Related errors
- Unable to refund charge; no Stripe chargeID!
- Charge has no transaction ID!
- Stripe charge call did not return an ID!
- Trying to refund an uncharged charge!
- Invalid currency format ('%s').
AI-assisted analysis of phacility/phabricator@5720a38cfe (2026-08-21).
Data as JSON: /api/errors/0869a5446bb55444.
Report an issue: GitHub.