phacility/phabricator · error · PhabricatorWorkerPermanentFailureException
Subscription is missing billing period information.
Error message
Subscription is missing billing period information.
What it means
The worker derives the billing window from the trigger.last-epoch and trigger.this-epoch keys that the scheduler writes into task data; last-epoch falls back to the subscription's creation date, so in practice this error means trigger.this-epoch is absent. The task was queued without normal trigger metadata and permanently fails, because the billing window cannot be reconstructed.
Source
Thrown at src/applications/phortune/worker/PhortuneSubscriptionWorker.php:241
/**
* 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();
$last_epoch = idx($data, 'trigger.last-epoch');
if (!$last_epoch) {
// If this is the first time the subscription is firing, use the
// creation date as the start of the billing period.
$last_epoch = $subscription->getDateCreated();
}
$this_epoch = idx($data, 'trigger.this-epoch');
if (!$last_epoch || !$this_epoch) {
throw new PhabricatorWorkerPermanentFailureException(
pht('Subscription is missing billing period information.'));
}
$period_length = ($this_epoch - $last_epoch);
if ($period_length <= 0) {
throw new PhabricatorWorkerPermanentFailureException(
pht(
'Subscription has invalid billing period.'));
}
if (empty($data['manual'])) {
if (PhabricatorTime::getNow() < $this_epoch) {
throw new Exception(
pht(
'Refusing to generate a subscription invoice for a billing period '.
'which ends in the future.'));
}
}View on GitHub (pinned to 5720a38cfe)
Solutions
- Do not hand-fire the worker: let the subscription's own trigger schedule it, which writes trigger.last-epoch and trigger.this-epoch automatically
- Inspect the failed task's data JSON in the daemon task detail view to see which epoch key is missing
- Re-save the subscription's billing settings to rebuild a clean trigger with fresh epoch data
Defensive patterns
Strategy: validation
Validate before calling
// When queueing the subscription worker, always include trigger epochs.
if (empty($data['trigger.this-epoch']) || empty($data['trigger.last-epoch'])) {
throw new Exception(pht('Refusing to queue subscription task without epochs.'));
} Prevention
- Never hand-fire PhortuneSubscriptionWorker; rely on the subscription trigger that writes epoch data
- When cloning tasks, copy the data array verbatim rather than rebuilding it
- Log task data at queue time so missing keys are visible in failure forensics
When it happens
Trigger: Manually queueing PhortuneSubscriptionWorker tasks without epoch data; code that clones or re-queues subscription tasks and drops the trigger.* keys; corrupted task data after an upgrade or partial import.
Common situations: Custom admin scripts that fire subscription billing by hand instead of relying on the trigger; debugging copies of production tasks; tooling that reconstructs task data from scratch.
Understand the failure class
Background: "Missing required field" and "field is required" errors: why libraries reject payloads that omit mandatory fields — this error's family across 20 libraries.
Related errors
- All members of the account ("%s") for this subscription ("%s
- Failed to load subscription with PHID "%s".
- Unable to load any of the members of the account ("%s") for
- The account ("%s") for this subscription ("%s") has no membe
- Subscription has invalid billing period.
AI-assisted analysis of phacility/phabricator@5720a38cfe (2026-08-21).
Data as JSON: /api/errors/385a578a1b13cf93.
Report an issue: GitHub.