phacility/phabricator · warning · PhutilArgumentUsageException

Specify a billing range with %s and %s, or use %s.

Error message

Specify a billing range with %s and %s, or use %s.

What it means

PhutilArgumentUsageException thrown by the phortune invoice workflow when none of --auto-range, --last, or --next is supplied. The workflow refuses to guess a billing range because an incorrect range can double-bill customers; the developer must either let the trigger schedule compute the range (--auto-range) or give the epoch range explicitly with both --last and --next.

Source

Thrown at src/applications/phortune/management/PhabricatorPhortuneManagementInvoiceWorkflow.php:92

    $now = $this->parseTimeArgument($now);
    if (!$now) {
      $now = PhabricatorTime::getNow();
    }

    $time_guard = PhabricatorTime::pushTime($now, date_default_timezone_get());

    $console->writeOut(
      "%s\n",
      pht(
        'Set current time to %s.',
        phabricator_datetime(PhabricatorTime::getNow(), $viewer)));

    $auto_range = $args->getArg('auto-range');
    $last_arg = $args->getArg('last');
    $next_arg = $args->getArg('next');

    if (!$auto_range && !$last_arg && !$next_arg) {
      throw new PhutilArgumentUsageException(
        pht(
          'Specify a billing range with %s and %s, or use %s.',
          '--last',
          '--next',
          '--auto-range'));
    } else if (!$auto_range & (!$last_arg || !$next_arg)) {
      throw new PhutilArgumentUsageException(
        pht(
          'When specifying %s or %s, you must specify both arguments '.
          'to define the beginning and end of the billing range.',
          '--last',
          '--next'));
    } else if (!$auto_range && ($last_arg && $next_arg)) {
      $last_time = $this->parseTimeArgument($args->getArg('last'));
      $next_time = $this->parseTimeArgument($args->getArg('next'));
    } else if ($auto_range && ($last_arg || $next_arg)) {
      throw new PhutilArgumentUsageException(
        pht(

View on GitHub (pinned to 5720a38cfe)

Solutions

  1. Pass --auto-range to let the subscription's trigger event define the range (requires the subscription to already be scheduled).
  2. Or pass both --last <epoch> and --next <epoch> to define the billing window explicitly.
  3. Encode the chosen form in your runbook/script so every invocation includes a complete range specification.

Example fix

# before
$ ./bin/phortune invoice --subscription PHID-PSUB-1234abcd

# after
$ ./bin/phortune invoice --subscription PHID-PSUB-1234abcd --auto-range
# or
$ ./bin/phortune invoice --subscription PHID-PSUB-1234abcd --last 1690000000 --next 1692600000
Defensive patterns

Strategy: validation

Validate before calling

// Enforce a complete range spec before invoking.
$has_auto = (bool) $auto_range;
$has_both = ((bool) $last_epoch) && ((bool) $next_epoch);
if (!$has_auto && !$has_both) {
  throw new InvalidArgumentException(
    'phortune invoice needs either --auto-range or both --last and --next.');
}

Prevention

When it happens

Trigger: Running `bin/phortune invoice --subscription <PHID>` with no range flags. The check is (!$auto_range && !$last_arg && !$next_arg), so any single stray flag like only --next also lands here only if the others are absent — with exactly one of --last/--next you get the companion error instead.

Common situations: Assuming the script defaults to the current billing period; building cron wrappers that only pass the subscription; upgrading from an older workflow that had no explicit range concept.

Related errors


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