phacility/phabricator · warning · PhutilArgumentUsageException

When specifying %s or %s, you must specify both arguments to

Error message

When specifying %s or %s, you must specify both arguments to define the beginning and end of the billing range.

What it means

PhutilArgumentUsageException thrown by the phortune invoice workflow when exactly one of --last / --next is given without --auto-range. A billing range is a closed interval: --last is the beginning epoch and --next the end epoch, and supplying only one half is ambiguous, so the workflow refuses rather than invent the missing bound (an invented bound risks double-billing).

Source

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

    $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(
          'Use either %s or %s and %s to specify the '.
          'billing range, but not both.',
          '--auto-range',
          '--last',
          '--next'));
    } else {
      $trigger = $subscription->getTrigger();

View on GitHub (pinned to 5720a38cfe)

Solutions

  1. Add the missing companion flag so both --last and --next are present.
  2. Compute the two epochs from the subscription's billing period boundaries before invoking.
  3. Prefer --auto-range when you just want the scheduled period and do not need custom bounds.

Example fix

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

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

Strategy: validation

Validate before calling

// Both halves of the interval must be present.
if (!$auto_range && ($last_epoch xor $next_epoch)) {
  throw new InvalidArgumentException(
    'Billing range is a closed interval: provide both --last and --next (or use --auto-range).');
}

Prevention

When it happens

Trigger: Running `... --subscription <PHID> --last 1690000000` (no --next), or `... --next 1692600000` (no --last), each without --auto-range. The condition (!$auto_range && (!$last_arg || !$next_arg)) fires when either half is missing.

Common situations: Scripts templating only the 'since' epoch; operators assuming --next defaults to now; flag names confused with the trigger daemon's naming ('trigger.last-epoch' / 'trigger.this-epoch' in the queued task).

Related errors


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