vercel/next.js · error · ImageError
"url" parameter is valid but upstream response timed out
Error message
"url" parameter is valid but upstream response timed out
What it means
Thrown by fetchExternalImage (ImageError 504) when fetching the upstream image URL times out. The fetch is wrapped in AbortSignal.timeout(7_000) (7 seconds); if it rejects with a TimeoutError, Next.js logs the href and returns a 504 to the client. This indicates the upstream image host is unreachable or too slow.
Source
Thrown at packages/next/src/server/image-optimizer.ts:894
'upstream image',
href,
'hostname resolved to private IP',
JSON.stringify(privateIps),
'If this is expected and you understand SSRF risk, use images.dangerouslyAllowLocalIP = true to continue.'
)
throw new ImageError(400, '"url" parameter is not allowed')
}
}
const res = await fetch(href, {
signal: AbortSignal.timeout(7_000),
redirect: 'manual',
}).catch((err) => err as Error)
if (res instanceof Error) {
const err = res as Error
if (err.name === 'TimeoutError') {
Log.error('upstream image response timed out for', href)
throw new ImageError(
504,
'"url" parameter is valid but upstream response timed out'
)
}
throw err
}
const locationHeader = res.headers.get('Location')
if (
isRedirect(res.status) &&
locationHeader &&
URL.canParse(locationHeader, href)
) {
if (count === 0) {
Log.error('upstream image response had too many redirects', href)
throw new ImageError(
508,
'"url" parameter is valid but upstream response is invalid'View on GitHub (pinned to 0ae8c72462)
Solutions
- Retry the request; timeouts are often transient.
- Verify the upstream image URL is reachable from the server (curl with timing from the host).
- Self-host/mirror the image locally or via a CDN edge closer to the server.
- If you control the timeout, consider caching the optimized image (images.minimumCacheTTL) to avoid repeated upstream fetches.
Example fix
# before /_next/image?url=https://slow-host.example/photo.jpg&w=640&q=75 # 504 # after # verify reachability and cache; mirror to a faster origin curl -I --max-time 10 https://slow-host.example/photo.jpg # then reference a faster/CDN-backed URL
Defensive patterns
Strategy: retry
Validate before calling
// Probe upstream reachability within the optimizer's timeout before serving
async function isUpstreamReachable(href: string, ms = 7000) {
const ctrl = new AbortController()
const t = setTimeout(() => ctrl.abort(), ms)
try {
const r = await fetch(href, { method: 'HEAD', signal: ctrl.signal })
return r.ok
} catch { return false } finally { clearTimeout(t) }
} Prevention
- Mirror/CDN large images close to the server to avoid timeouts.
- Set images.minimumCacheTTL so repeated requests don't re-fetch upstream.
- Monitor upstream image host latency and alert on slowdowns.
When it happens
Trigger: fetch(href) with a 7-second abort timeout rejects and err.name === 'TimeoutError'. The catch converts it to ImageError(504, '"url" parameter is valid but upstream response timed out').
Common situations: Upstream image server is slow or overloaded. Network latency between the Next.js server and the image host. A firewall or egress filter dropping packets so the connection hangs until timeout. Transient upstream outage.
Understand the failure class
- Timeouts: ETIMEDOUT, deadlines, and hung requests — what actually expires when a request times out.
Related errors
- "url" parameter is valid but upstream response is invalid
- "url" parameter is not allowed
- Failed to fetch ${url}
- Dev server did not become ready within ${timeoutMs}ms
- Server did not become ready within ${timeoutMs}ms
AI-assisted analysis of vercel/next.js@0ae8c72462 (2026-08-06).
Data as JSON: /api/errors/0ec56a42e8229f2b.
Report an issue: GitHub.