{"record":{"id":"528179559135b5d2","repo":"phacility/phabricator","slug":"unit-test-permanent","errorCode":null,"errorMessage":"Unit Test (Permanent)","messagePattern":"Unit Test \\(Permanent\\)","errorType":"exception","errorClass":"PhabricatorMetaMTAPermanentFailureException","httpStatus":null,"severity":"info","filePath":"src/applications/metamta/adapter/PhabricatorMailTestAdapter.php","lineNumber":58,"sourceCode":"  protected function validateOptions(array $options) {\n    PhutilTypeSpec::checkMap($options, array());\n  }\n\n  public function newDefaultOptions() {\n    return array();\n  }\n\n  public function supportsMessageIDHeader() {\n    return $this->supportsMessageID;\n  }\n\n  public function getGuts() {\n    return $this->guts;\n  }\n\n  public function sendMessage(PhabricatorMailExternalMessage $message) {\n    if ($this->failPermanently) {\n      throw new PhabricatorMetaMTAPermanentFailureException(\n        pht('Unit Test (Permanent)'));\n    }\n\n    if ($this->failTemporarily) {\n      throw new Exception(\n        pht('Unit Test (Temporary)'));\n    }\n\n    switch ($message->getMessageType()) {\n      case PhabricatorMailEmailMessage::MESSAGETYPE:\n        $guts = $this->newEmailGuts($message);\n        break;\n      case PhabricatorMailSMSMessage::MESSAGETYPE:\n        $guts = $this->newSMSGuts($message);\n        break;\n    }\n\n    $guts['did-send'] = true;","sourceCodeStart":40,"sourceCodeEnd":76,"githubUrl":"https://github.com/phacility/phabricator/blob/5720a38cfe95b00ca4be5016dd0d2f3195f4fa04/src/applications/metamta/adapter/PhabricatorMailTestAdapter.php#L40-L76","documentation":"PhabricatorMailTestAdapter is a fake mailer for unit tests and manual verification. Its setFailPermanently(true) flag arms sendMessage() to throw PhabricatorMetaMTAPermanentFailureException with 'Unit Test (Permanent)', simulating a permanent delivery failure so you can observe the mail queue marking a message as failed immediately instead of retrying. Seeing this means the mailer in play is the test adapter with failure injection enabled - it is test tooling, not a production error.","triggerScenarios":"Unit tests or scripts that construct the test adapter, call setFailPermanently(true), and then trigger a send (direct sendMessage() or through the mail worker); verifying that permanent failures set PhabricatorMailOutboundStatus::STATUS_FAIL without retry.","commonSituations":"Writing/running Phabricator mail-queue tests; QA exercising the permanent-failure path. If it appears outside tests, some code path built a test adapter with the flag set - production config of type 'test' never sets it (the adapter accepts no options at all).","solutions":["If you expected delivery: this path only runs when setFailPermanently(true) was called explicitly - find the caller; production mailers are configured in cluster.mailers with a real adapter type.","If testing: assert the outcome you instrumented - the mail should transition to 'fail' status immediately, with no worker retries.","Inspect outbound state with the MetaMTA mail UI or 'bin/mail' workflows to confirm the permanent-failure semantics you were testing."],"exampleFix":"// before (test)\n$mailer = id(new PhabricatorMailTestAdapter())->setFailPermanently(true);\n\n// after (test)\n$mailer = id(new PhabricatorMailTestAdapter());\n// or keep the flag and assert the permanent failure explicitly:\n//   assert($mail->getStatus() == PhabricatorMailOutboundStatus::STATUS_FAIL);","handlingStrategy":"validation","validationCode":"// Deployment guard: production installs must not enable failure injection.\nforeach (PhabricatorMetaMTAMail::newMailers(array()) as $mailer) {\n  if ($mailer->getAdapterType() === 'test' && $env !== 'test') {\n    warn('Test mailer configured outside a test environment.');\n  }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Only call setFailPermanently() inside test code that asserts the failed-mail state.","Keep type 'test' mailers on development installs only; audit cluster.mailers before promoting config."],"tags":["phabricator","metamta","testing","mail","failure-injection"],"backgroundTag":"test-failure-injection","analyzedSha":"5720a38cfe95b00ca4be5016dd0d2f3195f4fa04","analyzedAt":"2026-08-21T05:07:25.672Z","schemaVersion":2},"datasetVersion":"2026-08-21T11:28:35.574Z"}