{"record":{"id":"08c2442798aefdb5","repo":"phacility/phabricator","slug":"transaction-specifies-both-beforephid-and-befor","errorCode":null,"errorMessage":"Transaction specifies both \"beforePHID\" and \"beforePHIDs\". Specify only \"beforePHIDs\".","messagePattern":"Transaction specifies both \"beforePHID\" and \"beforePHIDs\"\\. Specify only \"beforePHIDs\"\\.","errorType":"validation","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"src/applications/maniphest/editor/ManiphestTransactionEditor.php","lineNumber":490,"sourceCode":"        'afterPHIDs' => array(),\n      );\n\n      // Normalize the legacy keys \"beforePHID\" and \"afterPHID\" keys to the\n      // modern format.\n      if (!empty($value['afterPHID'])) {\n        if ($value['afterPHIDs']) {\n          throw new Exception(\n            pht(\n              'Transaction specifies both \"afterPHID\" and \"afterPHIDs\". '.\n              'Specify only \"afterPHIDs\".'));\n        }\n        $value['afterPHIDs'] = array($value['afterPHID']);\n        unset($value['afterPHID']);\n      }\n\n      if (isset($value['beforePHID'])) {\n        if ($value['beforePHIDs']) {\n          throw new Exception(\n            pht(\n              'Transaction specifies both \"beforePHID\" and \"beforePHIDs\". '.\n              'Specify only \"beforePHIDs\".'));\n        }\n        $value['beforePHIDs'] = array($value['beforePHID']);\n        unset($value['beforePHID']);\n      }\n\n      foreach ($value['beforePHIDs'] as $phid) {\n        $relative_phids[] = $phid;\n      }\n\n      foreach ($value['afterPHIDs'] as $phid) {\n        $relative_phids[] = $phid;\n      }\n\n      $new[$key] = $value;\n    }","sourceCodeStart":472,"sourceCodeEnd":508,"githubUrl":"https://github.com/phacility/phabricator/blob/5720a38cfe95b00ca4be5016dd0d2f3195f4fa04/src/applications/maniphest/editor/ManiphestTransactionEditor.php#L472-L508","documentation":"The mirror of the 'after' rule: a column move transaction may use the modern 'beforePHIDs' list or the deprecated 'beforePHID' single string, never both. During normalization in buildMoveTransaction, a non-empty 'beforePHIDs' alongside an isset 'beforePHID' throws this Exception.","triggerScenarios":"A move value like {\"columnPHID\": \"PHID-PCOL-...\", \"beforePHID\": \"PHID-TASK-aaa\", \"beforePHIDs\": [\"PHID-TASK-bbb\"]} — typically from code that sets the legacy key first and then unconditionally initializes the list key.","commonSituations":"Refactoring old single-relative-position code to multi-position and leaving the old assignment on a code path that also populates the list. Default-value builders ($value += array('beforePHIDs' => ...)) combined with caller-supplied 'beforePHID'. Same-era documentation mixing both key styles.","solutions":["Use only \"beforePHIDs\": [\"PHID-TASK-aaa\"] and remove 'beforePHID' from the payload.","Make legacy-key normalization unconditional in your client: if you populate 'beforePHID', never also send 'beforePHIDs'.","Remember the parallel 'afterPHID'/'afterPHIDs' rule — fixing one side alone still leaves the transaction able to throw."],"exampleFix":"// before\n$value = array(\n  'columnPHID'  => $column_phid,\n  'beforePHID'  => $before_phid,\n  'beforePHIDs' => array($before_phid),\n);\n\n// after\n$value = array(\n  'columnPHID'  => $column_phid,\n  'beforePHIDs' => array($before_phid),\n);","handlingStrategy":"validation","validationCode":"if (isset($move['beforePHID'])) {\n  if (!empty($move['beforePHIDs'])) {\n    unset($move['beforePHID']); // conflicting formats; keep the list\n  } else {\n    $move['beforePHIDs'] = array($move['beforePHID']);\n    unset($move['beforePHID']);\n  }\n}","typeGuard":"function has_no_legacy_position_keys(array $move) {\n  return !isset($move['beforePHID']) && !isset($move['afterPHID']);\n}","tryCatchPattern":null,"preventionTips":["Use only 'beforePHIDs'/'afterPHIDs'; drop the singular legacy keys.","Guard default-value merging so legacy keys cannot coexist with lists.","Fix both before- and after-variants together when refactoring."],"tags":["phabricator","maniphest","workboard","transaction","legacy-key-conflict"],"backgroundTag":"conflicting-format-keys","analyzedSha":"5720a38cfe95b00ca4be5016dd0d2f3195f4fa04","analyzedAt":"2026-08-21T05:07:25.672Z","schemaVersion":2},"datasetVersion":"2026-08-21T11:28:35.574Z"}