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

  1. Locate the caller of setFailTemporarily(true) - it is always programmatic, never config-driven.
  2. If testing retries, watch the queue: each attempt schedules the worker again; after the retry limit the mail is marked failed.
  3. 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

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


AI-assisted analysis of phacility/phabricator@5720a38cfe (2026-08-21). Data as JSON: /api/errors/ffc93c4f2ecd1420. Report an issue: GitHub.