phacility/phabricator · error · PhabricatorWorkerPermanentFailureException
Failed to load subscription with PHID "%s".
Error message
Failed to load subscription with PHID "%s".
What it means
The queued billing task carries subscriptionPHID in its task data, and loadSubscription() re-loads it with an omnipotent-user PhortuneSubscriptionQuery. If the row is gone (almost always because the subscription was deleted), the query returns null and the worker throws a permanent failure. Retrying cannot resurrect a deleted subscription, so the queue discards the task.
Source
Thrown at src/applications/phortune/worker/PhortuneSubscriptionWorker.php:213
/**
* Load the subscription to generate an invoice for.
*
* @return PhortuneSubscription The subscription to invoice.
*/
private function loadSubscription() {
$viewer = PhabricatorUser::getOmnipotentUser();
$data = $this->getTaskData();
$subscription_phid = idx($data, 'subscriptionPHID');
$subscription = id(new PhortuneSubscriptionQuery())
->setViewer($viewer)
->withPHIDs(array($subscription_phid))
->executeOne();
if (!$subscription) {
throw new PhabricatorWorkerPermanentFailureException(
pht(
'Failed to load subscription with PHID "%s".',
$subscription_phid));
}
return $subscription;
}
/**
* Get the start and end epoch timestamps for this billing period.
*
* @param PhortuneSubscription The subscription being billed.
* @return pair<int, int> Beginning and end of the billing range.
*/
private function getBillingPeriodRange(PhortuneSubscription $subscription) {
$data = $this->getTaskData();
View on GitHub (pinned to 5720a38cfe)
Solutions
- Check the phortune_subscription table for the PHID shown in the failed task's data to confirm the subscription is really gone
- If the deletion was intentional, no action is needed: let the task record its permanent failure and move on
- If triggers keep firing, find and remove the orphaned row in the trigger (phabricator_trigger) table that keeps scheduling tasks for the dead subscription
Defensive patterns
Strategy: validation
Validate before calling
// Verify the subscription still exists before queueing billing work.
$subscription = id(new PhortuneSubscriptionQuery())
->setViewer(PhabricatorUser::getOmnipotentUser())
->withPHIDs(array($subscription_phid))
->executeOne();
if (!$subscription) {
return; // do not schedule billing for a subscription that is gone
} Try / catch
try {
// scheduling or executing subscription trigger tasks
} catch (PhabricatorWorkerPermanentFailureException $ex) {
if (strpos($ex->getMessage(), 'Failed to load subscription') !== false) {
// orphaned trigger: remove the trigger row instead of re-queueing
}
} Prevention
- Delete or cancel subscriptions before dropping their rows
- When re-queuing or cloning worker tasks, re-validate referenced PHIDs first
- Clean up trigger rows when subscriptions are removed programmatically
When it happens
Trigger: A subscription's periodic trigger task fires after the PhortuneSubscription row was deleted; or the task data was hand-edited or re-queued with a PHID that does not exist in the database.
Common situations: User deletes a subscription while its trigger task is already in the queue; restoring a database dump while keeping the old worker queue; scripts enqueueing worker tasks with stale or hand-copied PHIDs.
Related errors
- All members of the account ("%s") for this subscription ("%s
- Unable to load any of the members of the account ("%s") for
- The account ("%s") for this subscription ("%s") has no membe
- Subscription is missing billing period information.
- Subscription has invalid billing period.
AI-assisted analysis of phacility/phabricator@5720a38cfe (2026-08-21).
Data as JSON: /api/errors/ce1e676db87b6c7e.
Report an issue: GitHub.