next/image: /_next/image returns 500 (raw "fetch failed") when the remote host fails DNS or refuses the connection
Nobody has claimed this yet.
- Dominant language
- JavaScript
- Stars
- 142k
- Forks
- 32.5k
- Avg merge
- 2d 14h
- Merged PRs (30d)
- 351
Description
Link to the code that reproduces this issue
https://github.com/matias-berger-atlas/next-image-enotfound-500-repro
To Reproduce
- Clone the repro (next@16.3.4 pinned),
npm install next.config.tsallowsdoes-not-resolve.example.invalidinimages.remotePatterns;app/page.tsxrenders one<Image>from that hostnpm run build && npm startcurl -i 'http://localhost:3000/_next/image?url=https%3A%2F%2Fdoes-not-resolve.example.invalid%2Fa.jpg&w=640&q=75'
Current vs. Expected behavior
Current: 500 Internal Server Error, and the server logs
⨯ [TypeError: fetch failed]
[cause]: Error: getaddrinfo ENOTFOUND does-not-resolve.example.invalid
Same for ECONNREFUSED and TLS handshake errors: any rejection of the upstream fetch().
Expected: a client-visible upstream error status (502 or 404) like every other upstream failure in the optimizer already produces. In fetchExternalImage:
const res = await fetch(href, { signal: AbortSignal.timeout(7000), redirect: 'manual' }).catch((err) => err)
if (res instanceof Error) {
const err = res as Error
if (err.name === 'TimeoutError') {
throw new ImageError(504, '"url" parameter is valid but upstream response timed out')
}
throw err // <-- raw TypeError('fetch failed') escapes; the route has no status for it => 500
}
Upstream timeout -> 504. Upstream non-2xx -> ImageError(res.status). Upstream too large -> 413. Only a rejected fetch (DNS failure, connection refused, TLS error) is rethrown raw and becomes a 500 with a stack trace in the logs. Still the case on 16.4.0-canary.26.
Why it matters: a third-party image CDN going dark (a real case for us: mediavault.point2.com stopped resolving, ~21k images) turns into a flood of 500s on the app's own ingress and alerts, for something that is entirely the upstream's fault and that the client <img onError> already handles fine when given a 4xx/5xx.
Suggested fix (we run this as a pnpm patch today):
throw new ImageError(502, '"url" parameter is valid but upstream request failed')
Provide environment information
Next.js 16.3.4 (also reproduced on 16.3.0 and 16.4.0-canary.26), Node 22, Linux (standalone, self-hosted), and locally on macOS.
Which area(s) are affected?
Image (next/image)
Which stage(s) are affected?
next start (local), Other (self-hosted / standalone)
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with the linked reproduction, using next.config.ts, app/page.tsx, and the documented npm install, npm run build && npm start, and curl steps. Then inspect fetchExternalImage and its handling of rejected fetches. Done means DNS, connection-refused, and TLS failures return a client-visible upstream error such as 502 instead of an unhandled 500.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- javascript, nextjs, node.js
- Domain
- backend, web-dev
- Issue type
- Bug
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 78/100