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

  1. Inspect the response text in the error — Mailgun states the rejection reason
  2. Verify MAILGUN_API_KEY is the private API key of the correct Mailgun account and region (EU endpoints need the EU base URL)
  3. Confirm the sending domain is verified in Mailgun and matches the domain parsed from provider.from
  4. 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

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


AI-assisted analysis of nextauthjs/next-auth@a1a16a5a77 (2026-08-28). Data as JSON: /api/errors/5cf45d70bc23da12. Report an issue: GitHub.