Link to the code that reproduces this issue
https://github.com/matias-berger-atlas/next-image-enotfound-500-repro
To Reproduce
- Clone the repro ([email protected] pinned),
npm install
next.config.ts allows does-not-resolve.example.invalid in images.remotePatterns; app/page.tsx renders one <Image> from that host
npm run build && npm start
curl -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)
Link to the code that reproduces this issue
https://github.com/matias-berger-atlas/next-image-enotfound-500-repro
To Reproduce
npm installnext.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 logsSame for
ECONNREFUSEDand TLS handshake errors: any rejection of the upstreamfetch().Expected: a client-visible upstream error status (502 or 404) like every other upstream failure in the optimizer already produces. In
fetchExternalImage: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 on16.4.0-canary.26.Why it matters: a third-party image CDN going dark (a real case for us:
mediavault.point2.comstopped 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):
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)