phacility/phabricator · warning · Exception
This order can not be voided because it is not an invoice.
Error message
This order can not be voided because it is not an invoice.
What it means
assertCanVoidOrder() throws when getIsInvoice() is false: voiding is reserved for subscription-generated invoices, because a void marks an issued invoice as never-payable. Ordinary orders do not go through voiding - they are cancelled (before purchase) or refunded (after charge).
Source
Thrown at src/applications/phortune/storage/PhortuneCart.php:545
public function assertCanRefundOrder() {
switch ($this->getStatus()) {
case self::STATUS_BUILDING:
throw new Exception(
pht(
'This order can not be refunded because the application has not '.
'finished building it yet.'));
case self::STATUS_READY:
throw new Exception(
pht(
'This order can not be refunded because it has not been placed.'));
}
return $this->getImplementation()->assertCanRefundOrder($this);
}
public function assertCanVoidOrder() {
if (!$this->getIsInvoice()) {
throw new Exception(
pht(
'This order can not be voided because it is not an invoice.'));
}
switch ($this->getStatus()) {
case self::STATUS_READY:
break;
default:
throw new Exception(
pht(
'This order can not be voided because it is not ready for '.
'payment.'));
}
return null;
}
View on GitHub (pinned to 5720a38cfe)
Solutions
- Check $cart->getIsInvoice() before offering the void action.
- For non-invoice orders use cancel (unplaced) or refund (charged) instead.
- Filter lists so void only appears on subscription invoice carts.
Example fix
// before
$cart->assertCanVoidOrder(); // throws 'This order can not be voided because it is not an invoice.'
// after
if ($cart->getIsInvoice()) {
$cart->assertCanVoidOrder();
// proceed with void
} else {
// use canCancelOrder()/canRefundOrder() paths for normal orders
} Defensive patterns
Strategy: validation
Validate before calling
if (!$cart->getIsInvoice()) {
// void applies only to subscription invoices; use cancel or refund instead
return $this->newDialog()->setTitle(pht('Not an Invoice'));
} Type guard
function isInvoiceCart(PhortuneCart $cart) {
return (bool)$cart->getIsInvoice();
} Prevention
- Offer void only on carts with getIsInvoice() true.
- Map intents correctly: cancel before purchase, refund after charge, void only for invoices.
- Keep void actions out of generic order tooling.
When it happens
Trigger: Calling assertCanVoidOrder() on a cart created by a normal purchase flow (isInvoice is 0/absent), e.g. pointing a void action at a user-initiated order instead of a subscription invoice.
Common situations: Generic order-management tooling applying the void action to all carts; confusion between void (invoice-only), cancel, and refund in custom controllers.
Related errors
- This order can not be voided because it is not ready for pay
- This order can not be cancelled because the application has
- This order can not be cancelled because it has not been plac
- This order can not be refunded because the application has n
- This order can not be refunded because it has not been place
AI-assisted analysis of phacility/phabricator@5720a38cfe (2026-08-21).
Data as JSON: /api/errors/28788ef2d7e5a847.
Report an issue: GitHub.