phacility/phabricator · warning · Exception

Refusing to generate a subscription invoice for a billing pe

Error message

Refusing to generate a subscription invoice for a billing period which ends in the future.

What it means

A safety valve in the billing worker: unless the task data carries the manual flag, it refuses to invoice a period whose end (this_epoch) is still in the future. Unlike its sibling errors this is a plain Exception, so the queue treats it as a temporary failure and retries with backoff; it self-heals once the period actually elapses.

Source

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

      $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.'));
      }
    }

    return array($last_epoch, $this_epoch);
  }

}

View on GitHub (pinned to 5720a38cfe)

Solutions

  1. Wait: the task retries automatically and succeeds once the current time passes this_epoch
  2. Fix clock skew and keep date.timezone consistent across web and daemon hosts
  3. To invoice early on purpose, use the subscription's invoice-now action, which queues the task with the manual flag set

Example fix

// before: firing the worker for a period that has not elapsed
$data = array('subscriptionPHID' => $subscription->getPHID());

// after: mark the run as manual to permit early invoicing
$data = array(
  'subscriptionPHID' => $subscription->getPHID(),
  'manual' => true,
);
Defensive patterns

Strategy: retry

Try / catch

try {
  // invoke subscription billing manually
} catch (Exception $ex) {
  if (strpos($ex->getMessage(), 'ends in the future') !== false) {
    // Temporary by design: reschedule the run for $this_epoch; do not alert.
  }
}

Prevention

When it happens

Trigger: The trigger fires before this_epoch has passed (scheduler race, clock skew between the scheduling and executing hosts), or someone fires the worker early without setting data['manual'].

Common situations: Clock drift between hosts in multi-server installs; testing billing with artificially shifted clocks; trying to invoice early by invoking the worker directly instead of the UI action.

Related errors


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