{"record":{"id":"01d643c84cd56ea9","repo":"phacility/phabricator","slug":"specify-either-promote-or-demote-but-not-both","errorCode":null,"errorMessage":"Specify either --promote or --demote, but not both.","messagePattern":"Specify either --promote or --demote, but not both\\.","errorType":"exception","errorClass":"PhutilArgumentUsageException","httpStatus":null,"severity":"warning","filePath":"src/applications/repository/management/PhabricatorRepositoryManagementThawWorkflow.php","lineNumber":61,"sourceCode":"            'name' => 'repositories',\n            'wildcard' => true,\n          ),\n        ));\n  }\n\n  public function execute(PhutilArgumentParser $args) {\n    $viewer = $this->getViewer();\n\n    $promote = $args->getArg('promote');\n    $demote = $args->getArg('demote');\n\n    if (!$promote && !$demote) {\n      throw new PhutilArgumentUsageException(\n        pht('You must choose a device to --promote or --demote.'));\n    }\n\n    if ($promote && $demote) {\n      throw new PhutilArgumentUsageException(\n        pht('Specify either --promote or --demote, but not both.'));\n    }\n\n    $target_name = nonempty($promote, $demote);\n\n    $devices = id(new AlmanacDeviceQuery())\n      ->setViewer($viewer)\n      ->withNames(array($target_name))\n      ->execute();\n    if (!$devices) {\n      $service = id(new AlmanacServiceQuery())\n        ->setViewer($viewer)\n        ->withNames(array($target_name))\n        ->executeOne();\n\n      if (!$service) {\n        throw new PhutilArgumentUsageException(\n          pht('No device or service named \"%s\" exists.', $target_name));","sourceCodeStart":43,"sourceCodeEnd":79,"githubUrl":"https://github.com/phacility/phabricator/blob/5720a38cfe95b00ca4be5016dd0d2f3195f4fa04/src/applications/repository/management/PhabricatorRepositoryManagementThawWorkflow.php#L43-L79","documentation":"thaw's `--promote` (accept a device's version of the repository) and `--demote` (reject it) are opposite operations on the same target, so exactly one must be given. Supplying both is contradictory and rejected with this PhutilArgumentUsageException before any Almanac query runs.","triggerScenarios":"Running `./bin/repository thaw --promote <device> --demote <device>` — any invocation where both `$promote` and `$demote` are truthy.","commonSituations":"Cut-and-paste command assembly from incident runbooks; scripts forwarding both options from unset/overlapping configuration.","solutions":["Keep exactly one operation per invocation: `--promote <device>` to trust its version, or `--demote <device>` to discard it.","Run the two operations as separate sequential commands if both are genuinely needed."],"exampleFix":"# before\n./bin/repository thaw --promote repo-01 --demote repo-02\n# Usage exception: Specify either --promote or --demote, but not both.\n\n# after: two separate invocations\n./bin/repository thaw --demote repo-02\n./bin/repository thaw --promote repo-01","handlingStrategy":"validation","validationCode":"# Allow exactly one operation\nif [ -n \"$PROMOTE\" ] && [ -n \"$DEMOTE\" ]; then\n  echo \"pass either --promote or --demote, not both\" >&2; exit 2\nfi\n./bin/repository thaw ${PROMOTE:+--promote \"$PROMOTE\"} ${DEMOTE:+--demote \"$DEMOTE\"}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Model thaw as a single operation per invocation in scripts; chain separate commands when both are needed.","Validate the operation enum (`promote`|`demote`) before building the command line."],"tags":["php","phabricator","cli","thaw","clustering","flags","usage-error"],"backgroundTag":"mutually-exclusive-flags","analyzedSha":"5720a38cfe95b00ca4be5016dd0d2f3195f4fa04","analyzedAt":"2026-08-21T05:07:25.672Z","schemaVersion":2},"datasetVersion":"2026-08-21T11:28:35.574Z"}