phacility/phabricator · error · PhabricatorWorkerPermanentFailureException

All members of the account ("%s") for this subscription ("%s

Error message

All members of the account ("%s") for this subscription ("%s") are disabled.

What it means

The Phortune subscription billing worker (PhortuneSubscriptionWorker) throws PhabricatorWorkerPermanentFailureException with this message when every member of the subscription's Phortune account is disabled. Automatic billing needs a real, enabled user to act as when creating the invoice cart; with no such member the task fails permanently and will not be retried by the daemon.

Source

Thrown at src/applications/phortune/worker/PhortuneSubscriptionWorker.php:89

        $message = pht(
          'All members of the account ("%s") for this subscription ("%s") '.
          'are disabled.',
          $account->getPHID(),
          $subscription->getPHID());
      } else if ($account->getMemberPHIDs()) {
        $message = pht(
          'Unable to load any of the members of the account ("%s") for this '.
          'subscription ("%s").',
          $account->getPHID(),
          $subscription->getPHID());
      } else {
        $message = pht(
          'The account ("%s") for this subscription ("%s") has no '.
          'members.',
          $account->getPHID(),
          $subscription->getPHID());
      }
      throw new PhabricatorWorkerPermanentFailureException($message);
    }

    $cart = $account->newCart($actor, $cart_implementation, $merchant);

    $purchase = $cart->newPurchase($actor, $product);

    $purchase
      ->setBasePriceAsCurrency($currency)
      ->setMetadataValue('subscriptionPHID', $subscription->getPHID())
      ->setMetadataValue('epoch.start', $last_epoch)
      ->setMetadataValue('epoch.end', $next_epoch)
      ->save();

    $cart
      ->setSubscriptionPHID($subscription->getPHID())
      ->setIsInvoice(1)
      ->save();

View on GitHub (pinned to 5720a38cfe)

Solutions

  1. Re-enable at least one member of the account (or add an active manager to it) so the next billing trigger finds an actor.
  2. Cancel the subscription if it is no longer wanted, so triggers stop firing and the queue stops accumulating permanent failures.
  3. Move subscriptions to a shared account that always keeps at least one enabled member.
  4. Monitor the daemon task queue for permanent failures to catch this before dunning emails stop going out.
Defensive patterns

Strategy: validation

Validate before calling

$members = id(new PhabricatorPeopleQuery())
  ->setViewer(PhabricatorUser::getOmnipotentUser())
  ->withPHIDs($account->getMemberPHIDs())
  ->execute();
$has_actor = false;
foreach ($members as $member) {
  if (!$member->getIsDisabled()) {
    $has_actor = true;
    break;
  }
}
if (!$has_actor) {
  // do not rely on automatic billing: fix membership or cancel the subscription
}

Prevention

When it happens

Trigger: A subscription trigger fires for periodic billing while all users returned by PhabricatorPeopleQuery for $account->getMemberPHIDs() have getIsDisabled() true - the worker skips them, finds no actor, and throws.

Common situations: Employees disabled during offboarding while their personal accounts still carry active subscriptions; shared team accounts whose every member was deactivated; abandoned test subscriptions on accounts whose members were all banned.

Related errors


AI-assisted analysis of phacility/phabricator@5720a38cfe (2026-08-21). Data as JSON: /api/errors/13dfcb05d0cb2f89. Report an issue: GitHub.