nextauthjs/next-auth · error · Error
Mailgun error: + (await res.text())
Error message
Mailgun error: + (await res.text())
What it means
Thrown when Mailgun's messages API returns a non-OK status after the multipart form was sent. The provider includes Mailgun's raw response text (usually JSON or HTML error output) in the message. This means the request reached Mailgun but was rejected — authentication, domain, or payload problems — so no verification email was delivered.
Source
Thrown at packages/core/src/providers/mailgun.ts:94
if (!domain) throw new Error("malformed Mailgun domain")
const form = new FormData()
form.append("from", `${provider.name} <${provider.from}>`)
form.append("to", to)
form.append("subject", `Sign in to ${host}`)
form.append("html", html({ host, url, theme }))
form.append("text", text({ host, url }))
const res = await fetch(`https://${apiServer}/v3/${domain}/messages`, {
method: "POST",
headers: {
Authorization: `Basic ${btoa(`api:${provider.apiKey}`)}`,
},
body: form,
})
if (!res.ok) throw new Error("Mailgun error: " + (await res.text()))
},
options: config,
}
}
View on GitHub (pinned to a1a16a5a77)
Solutions
- Inspect the response text in the error — Mailgun states the rejection reason
- Verify MAILGUN_API_KEY is the private API key of the correct Mailgun account and region (EU endpoints need the EU base URL)
- Confirm the sending domain is verified in Mailgun and matches the domain parsed from provider.from
- If on a sandbox domain, add the recipient to Mailgun's Authorized Recipients list
Example fix
// before
Mailgun({ apiKey: process.env.MAILGUN_API_KEY }) // key from old account -> 401
// after
// use the correct regional key + verified domain
Mailgun({
apiKey: process.env.MAILGUN_API_KEY,
from: "Auth.js <no-reply@mg.your-verified-domain.com>",
}) Defensive patterns
Strategy: try-catch
Validate before calling
if (!process.env.MAILGUN_API_KEY) throw new Error('MAILGUN_API_KEY is not set')
if (!/^[^\s@]+@[^\s@]+$/.test(provider.from ?? '')) throw new Error('Mailgun from must be a valid address on a verified domain') Type guard
function isMailgunConfigured(p: { apiKey?: string; from?: string }): p is { apiKey: string; from: string } {
return !!p.apiKey && !!p.from && p.from.includes('@')
} Try / catch
try {
await sendVerificationRequest(params)
} catch (e) {
const msg = e instanceof Error ? e.message : String(e)
if (msg.includes('401')) console.error('Mailgun auth failed: check MAILGUN_API_KEY')
else console.error('Mailgun send failed:', msg) // response text has the reason
} Prevention
- Use the correct private API key for your account's region (US/EU base URL)
- Verify the sending domain in Mailgun and keep provider.from on it
- On sandbox domains, pre-authorize recipient addresses
- Inspect res.text() output in the error message — Mailgun reports the exact reason
When it happens
Trigger: POST to https://api.mailgun.net (domain-derived endpoint) with Basic auth api:API_KEY returns 401 (bad key), 400 (bad form field / unverified domain / sandbox domain not authorized for recipient), 402/429 (limits), or 5xx. The check `if (!res.ok)` triggers the throw with the response text.
Common situations: Wrong or revoked MAILGUN_API_KEY; sending from an unverified domain; using the EU vs US host mismatch; trying to send to un-authorized recipients on a Mailgun sandbox domain in test mode.
Related errors
- Loops Send Error: ${JSON.stringify(await res.json())}
- Forward Email error: ${JSON.stringify(await res.json())}
- malformed Mailgun domain
- Another account already exists with the same e-mail address
- Verification
AI-assisted analysis of nextauthjs/next-auth@a1a16a5a77 (2026-08-28).
Data as JSON: /api/errors/5cf45d70bc23da12.
Report an issue: GitHub.