{"record":{"id":"1dfea439f2246a94","repo":"phacility/phabricator","slug":"you-can-not-query-subscriptions-for-a-merchant-you","errorCode":null,"errorMessage":"You can not query subscriptions for a merchant you do not control.","messagePattern":"You can not query subscriptions for a merchant you do not control\\.","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"src/applications/phortune/query/PhortuneSubscriptionSearchEngine.php","lineNumber":59,"sourceCode":"    $saved = new PhabricatorSavedQuery();\n\n    return $saved;\n  }\n\n  public function buildQueryFromSavedQuery(PhabricatorSavedQuery $saved) {\n    $query = id(new PhortuneSubscriptionQuery());\n\n    $viewer = $this->requireViewer();\n\n    $merchant = $this->getMerchant();\n    $account = $this->getAccount();\n    if ($merchant) {\n      $can_edit = PhabricatorPolicyFilter::hasCapability(\n        $viewer,\n        $merchant,\n        PhabricatorPolicyCapability::CAN_EDIT);\n      if (!$can_edit) {\n        throw new Exception(\n          pht(\n            'You can not query subscriptions for a merchant you do not '.\n            'control.'));\n      }\n      $query->withMerchantPHIDs(array($merchant->getPHID()));\n    } else if ($account) {\n      $can_edit = PhabricatorPolicyFilter::hasCapability(\n        $viewer,\n        $account,\n        PhabricatorPolicyCapability::CAN_EDIT);\n      if (!$can_edit) {\n        throw new Exception(\n          pht(\n            'You can not query subscriptions for an account you are not '.\n            'a member of.'));\n      }\n      $query->withAccountPHIDs(array($account->getPHID()));\n    } else {","sourceCodeStart":41,"sourceCodeEnd":77,"githubUrl":"https://github.com/phacility/phabricator/blob/5720a38cfe95b00ca4be5016dd0d2f3195f4fa04/src/applications/phortune/query/PhortuneSubscriptionSearchEngine.php#L41-L77","documentation":"Thrown by PhortuneSubscriptionSearchEngine when the query is scoped to a merchant the viewer cannot edit. Merchant-scoped subscription listings expose billing data for every customer of the merchant, so Phortune requires the CAN_EDIT capability on the merchant (manager level), verified with PhabricatorPolicyFilter::hasCapability. This is an authorization guard, not a generic policy exception.","triggerScenarios":"Requesting a merchant-scoped subscription list (e.g. /phortune/subscription/?merchant=...) or calling the engine with a merchant set, as a user for whom PhabricatorPolicyFilter::hasCapability($viewer, $merchant, CAN_EDIT) returns false.","commonSituations":"A paying customer bookmarking the merchant billing screen instead of their account screen; a former manager whose merchant edit permission was revoked; custom application controllers linking merchant subscription lists for ordinary account members.","solutions":["View subscriptions from the account context instead (the subscriptions on your own Phortune account).","Have the merchant owner add the user as a merchant manager so CAN_EDIT is granted.","In custom UI, gate the merchant link with PhabricatorPolicyFilter::hasCapability(..., PhabricatorPolicyCapability::CAN_EDIT) before rendering it."],"exampleFix":"// before\n$engine = id(new PhortuneSubscriptionSearchEngine())\n  ->setViewer($viewer)\n  ->setMerchant($merchant);\n$response = $engine->buildResponse($request, $saved_query); // throws for non-managers\n\n// after\n$can_edit = PhabricatorPolicyFilter::hasCapability(\n  $viewer,\n  $merchant,\n  PhabricatorPolicyCapability::CAN_EDIT);\nif (!$can_edit) {\n  return new Aphront403Response();\n}\n$response = $engine->buildResponse($request, $saved_query);","handlingStrategy":"validation","validationCode":"$can_edit = PhabricatorPolicyFilter::hasCapability(\n  $viewer,\n  $merchant,\n  PhabricatorPolicyCapability::CAN_EDIT);\nif (!$can_edit) {\n  return new Aphront403Response(); // or fall back to account-scoped view\n}\n// now safe to scope the engine to this merchant","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Gate merchant-scoped billing links on PhabricatorPolicyFilter::hasCapability(..., CAN_EDIT).","Default users to their account-scoped subscription list, not the merchant one.","Keep merchant manager grants in sync when staff roles change."],"tags":["phortune","phabricator","php","policy","authorization","subscriptions"],"backgroundTag":"policy-capability-denied","analyzedSha":"5720a38cfe95b00ca4be5016dd0d2f3195f4fa04","analyzedAt":"2026-08-21T05:07:25.672Z","schemaVersion":2},"datasetVersion":"2026-08-21T11:28:35.574Z"}