phacility/phabricator · info · Exception
Unit Test (Temporary)
Error message
Unit Test (Temporary)
What it means
The other failure-injection mode of PhabricatorMailTestAdapter: setFailTemporarily(true) makes sendMessage() throw a plain Exception with 'Unit Test (Temporary)'. Unlike the permanent variant, a plain exception from a mailer is treated by PhabricatorMetaMTAWorker as a transient failure - the message stays queued and the worker retries with backoff. It exists so tests can exercise retry behavior.
Source
Thrown at src/applications/metamta/adapter/PhabricatorMailTestAdapter.php:63
return array();
}
public function supportsMessageIDHeader() {
return $this->supportsMessageID;
}
public function getGuts() {
return $this->guts;
}
public function sendMessage(PhabricatorMailExternalMessage $message) {
if ($this->failPermanently) {
throw new PhabricatorMetaMTAPermanentFailureException(
pht('Unit Test (Permanent)'));
}
if ($this->failTemporarily) {
throw new Exception(
pht('Unit Test (Temporary)'));
}
switch ($message->getMessageType()) {
case PhabricatorMailEmailMessage::MESSAGETYPE:
$guts = $this->newEmailGuts($message);
break;
case PhabricatorMailSMSMessage::MESSAGETYPE:
$guts = $this->newSMSGuts($message);
break;
}
$guts['did-send'] = true;
$this->guts = $guts;
}
public function getBody() {
return idx($this->guts, 'body');View on GitHub (pinned to 5720a38cfe)
Solutions
- Locate the caller of setFailTemporarily(true) - it is always programmatic, never config-driven.
- If testing retries, watch the queue: each attempt schedules the worker again; after the retry limit the mail is marked failed.
- Remove the flag when you want the test adapter to 'deliver' normally (it just records guts).
Example fix
// before (test) $mailer = id(new PhabricatorMailTestAdapter())->setFailTemporarily(true); // after (test) $mailer = id(new PhabricatorMailTestAdapter());
Defensive patterns
Strategy: validation
Validate before calling
// In tests that do not target retry behavior, never arm the flag.
$mailer = id(new PhabricatorMailTestAdapter());
if ($testing_retries) {
$mailer->setFailTemporarily(true);
} Prevention
- Scope setFailTemporarily() to tests that explicitly assert worker retry counts.
- Remember the semantics: a plain Exception from sendMessage() means temporary failure and the worker retries with backoff.
When it happens
Trigger: Tests or scripts that construct the test adapter, call setFailTemporarily(true), and send a message; verifying that the worker re-queues PhabricatorMetaMTAWorker tasks and eventually fails the mail after exhausting retries.
Common situations: Writing Phabricator mail-retry tests; QA simulating flaky SMTP. If observed outside tests, the same rule applies: only explicit setFailTemporarily(true) enables it - config type 'test' accepts no options.
Related errors
- Unit Test (Permanent)
- err:exception
- Webhook request ("%s", to "%s") failed (%s / %s). The reques
- Adapter ("%s") is configured for medium "%s", but this is no
- Mailer ("%s") is attempting to access unknown option ("%s").
AI-assisted analysis of phacility/phabricator@5720a38cfe (2026-08-21).
Data as JSON: /api/errors/ffc93c4f2ecd1420.
Report an issue: GitHub.