phacility/phabricator · error · Exception
Request failed with errors: %s.
Error message
Request failed with errors: %s.
What it means
The Mailgun API answered with valid JSON, but the decoded object has no 'id' key - Mailgun only includes 'id' when a message is queued. The adapter therefore treats the response as a delivery failure and rethrows Mailgun's own 'message' field as the exception text. Note the code reads $response['message'] unconditionally, so a response with neither 'id' nor 'message' also produces an undefined-index error on top.
Source
Thrown at src/applications/metamta/adapter/PhabricatorMailMailgunAdapter.php:129
$attachment->getData(),
$attachment->getFilename(),
$attachment->getMimeType());
}
list($body) = $future->resolvex();
$response = null;
try {
$response = phutil_json_decode($body);
} catch (PhutilJSONParserException $ex) {
throw new PhutilProxyException(
pht('Failed to JSON decode response.'),
$ex);
}
if (!idx($response, 'id')) {
$message = $response['message'];
throw new Exception(
pht(
'Request failed with errors: %s.',
$message));
}
}
}
View on GitHub (pinned to 5720a38cfe)
Solutions
- Read the exception text - it is Mailgun's own error message and names the problem ('Domain not found: ...', 'Sandbox subdomains...', 'unauthorized', 401/403 messages).
- Make sure the mailer's 'domain' and 'api-key' options belong to the same Mailgun account and the domain is verified (Mailgun dashboard, Sending > Domains).
- Send from an address on the verified domain (or from the sandbox postmaster address when deliberately testing).
- Check account status and quotas in the Mailgun dashboard if the message indicates limits or suspension.
Example fix
// before: from-address on a domain Mailgun has not verified
$mail->setFrom('no-reply@unverified-domain.net');
// after: from-address on the verified sending domain
$mail->setFrom('no-reply@mg.example.com'); Defensive patterns
Strategy: try-catch
Try / catch
try {
$adapter->sendMessage($message);
} catch (Exception $ex) {
$text = $ex->getMessage();
// The text is Mailgun's own 'message' field: classify it.
if (preg_match('/Domain not found|Sandbox subdomains|unauthorized/i', $text)) {
// permanent: stop retrying, alert the admin to fix domain/api-key
$message->setStatus(PhabricatorMailOutboundStatus::STATUS_FAIL);
} else {
throw $ex; // let the worker retry
}
} Prevention
- Verify the Mailgun domain and from-address before switching a mailer to production.
- Keep the Mailgun dashboard open when debugging - the exception text maps 1:1 to its sending logs.
- Run bin/mail send-test after key or domain changes.
When it happens
Trigger: sendMessage() through the mailgun adapter with: an API key belonging to a different account than the configured 'domain'; a 'from' address on a domain Mailgun has not verified for that account ('Sandbox subdomains are for test purposes only'); malformed or rejected recipients; suspended account/quota exhaustion - any JSON response lacking 'id'.
Common situations: Sandbox/test domain left in cluster.mailers after go-live while production mail uses a real 'from' domain; API key rotated in Mailgun but not in Phabricator; sender domain not (re)verified after DNS changes.
Related errors
- Failed to JSON decode response.
- Mail signature is not valid. Check your Mailgun API key.
- Adapter ("%s") is configured for medium "%s", but this is no
- Mailer ("%s") is attempting to access unknown option ("%s").
- Unit Test (Permanent)
AI-assisted analysis of phacility/phabricator@5720a38cfe (2026-08-21).
Data as JSON: /api/errors/00b73d0adcc380ad.
Report an issue: GitHub.