{"record":{"id":"30ee440a9d2e6eae","repo":"phacility/phabricator","slug":"the-email-address-s-is-already-attached-to-this","errorCode":null,"errorMessage":"The email address \"%s\" is already attached to this account.","messagePattern":"The email address \"(.+?)\" is already attached to this account\\.","errorType":"validation","errorClass":"PhabricatorApplicationTransactionValidationException","httpStatus":null,"severity":"error","filePath":"src/applications/phortune/editor/PhortuneAccountEmailEditor.php","lineNumber":33,"sourceCode":"    return pht('%s created this account email.', $author);\n  }\n\n  protected function didCatchDuplicateKeyException(\n    PhabricatorLiskDAO $object,\n    array $xactions,\n    Exception $ex) {\n\n    $errors = array();\n\n    $errors[] = new PhabricatorApplicationTransactionValidationError(\n      PhortuneAccountEmailAddressTransaction::TRANSACTIONTYPE,\n      pht('Duplicate'),\n      pht(\n        'The email address \"%s\" is already attached to this account.',\n        $object->getAddress()),\n      null);\n\n    throw new PhabricatorApplicationTransactionValidationException($errors);\n  }\n\n}\n","sourceCodeStart":15,"sourceCodeEnd":37,"githubUrl":"https://github.com/phacility/phabricator/blob/5720a38cfe95b00ca4be5016dd0d2f3195f4fa04/src/applications/phortune/editor/PhortuneAccountEmailEditor.php#L15-L37","documentation":"PhortuneAccountEmailEditor catches the duplicate-key failure from the storage layer when saving a PhortuneAccountEmailAddress whose address already exists on the account, and rethrows it as a PhabricatorApplicationTransactionValidationException with a 'Duplicate' field error naming the offending address. This is a designed validation path: the unique constraint on (account, address) is enforced at the database level and translated into a user-facing transaction error rather than a raw crash.","triggerScenarios":"Applying an edit transaction (TRANSACTIONTYPE on PhortuneAccountEmailAddressTransaction) that adds an address equal to one already attached to the same Phortune account — e.g. re-adding 'billing@example.com' after it was already verified. The catch block fires when insert/update hits the unique index and Lisk raises a duplicate exception.","commonSituations":"Double form submission or impatient re-click on 'Add Email'; re-inviting an address that is attached but not yet verified; copy-paste retries after a session-expired error page; scripts replaying account-email edits idempotently without deduping.","solutions":["Before applying, load the account's existing email addresses and skip/flag any address already attached (dedupe on the client of the editor).","Catch PhabricatorApplicationTransactionValidationException in the controller and render getErrors() as form field errors — that is exactly what the exception carries.","Guard the form against double submission (disable the button on submit, or accept a one-time token) so the second insert never happens.","If the address exists but is unverified, resend verification to the existing row instead of creating a second one."],"exampleFix":"// before\nid(new PhortuneAccountEmailEditor())\n  ->setActor($viewer)\n  ->setContentSource($content_source)\n  ->applyTransactions($email, $xactions);\n\n// after\n$existing = id(new PhortuneAccountEmailQuery())\n  ->setViewer($viewer)\n  ->withAccountPHIDs(array($account->getPHID()))\n  ->withAddresses(array($raw_address))\n  ->execute();\nif ($existing) {\n  $e_address = pht('Duplicate');\n  $errors[] = pht(\n    'The email address \"%s\" is already attached to this account.',\n    $raw_address);\n  return $this->buildEditorResponse($errors);\n}\nid(new PhortuneAccountEmailEditor())\n  ->setActor($viewer)\n  ->setContentSource($content_source)\n  ->applyTransactions($email, $xactions);","handlingStrategy":"try-catch","validationCode":"// Pre-flight: does this address already exist on the account?\n$attached = id(new PhortuneAccountEmailQuery())\n  ->setViewer($viewer)\n  ->withAccountPHIDs(array($account->getPHID()))\n  ->withAddresses(array($address))\n  ->execute();\nif ($attached) {\n  // Show the duplicate error in the form; do not apply transactions.\n  $e_address = pht('Duplicate');\n  $errors[] = pht(\n    'The email address \"%s\" is already attached to this account.',\n    $address);\n}","typeGuard":null,"tryCatchPattern":"try {\n  id(new PhortuneAccountEmailEditor())\n    ->setActor($viewer)\n    ->setContentSource($content_source)\n    ->applyTransactions($object, $xactions);\n} catch (PhabricatorApplicationTransactionValidationException $ex) {\n  // The editor already packaged the duplicate as a field error;\n  // re-render the form with $ex->getErrors() instead of crashing.\n  return $this->buildFormResponse($object, $ex->getErrors());\n}","preventionTips":["Disable the submit button on first click so double submissions never reach the editor.","Normalize addresses (trim; lowercase domain) before comparing or inserting.","For re-adds of unverified addresses, resend verification on the existing row rather than creating a new one.","Treat a unique-index violation in editors as a validation result, never as an unexpected 500."],"tags":["php","phabricator","phortune","email","duplicate","unique-constraint","validation"],"backgroundTag":"duplicate-unique-constraint","analyzedSha":"5720a38cfe95b00ca4be5016dd0d2f3195f4fa04","analyzedAt":"2026-08-21T05:07:25.672Z","schemaVersion":2},"datasetVersion":"2026-08-21T11:28:35.574Z"}