vercel/next.js · error · ImageError
"url" parameter is valid but upstream response is invalid
Error message
"url" parameter is valid but upstream response is invalid
What it means
Thrown by fetchExternalImage (ImageError 508) when the upstream returns a redirect (301/302/303/307/308) with a parseable Location header but the redirect counter has hit zero (default 3 hops exhausted). fetchExternalImage recurses with count-1 on each redirect; when count===0 it stops and reports the loop. The status 508 (Loop Detected) signals too many redirects.
Source
Thrown at packages/next/src/server/image-optimizer.ts:910
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'
)
}
const redirect = new URL(locationHeader, href).href
return fetchExternalImage(
redirect,
dangerouslyAllowLocalIP,
maximumResponseBody,
count - 1
)
}
if (!res.ok) {
Log.error('upstream image response failed for', href, res.status)
throw new ImageError(
res.status,
'"url" parameter is valid but upstream response is invalid'View on GitHub (pinned to 0ae8c72462)
Solutions
- Resolve the final image URL (follow redirects manually) and configure that direct URL in remotePatterns.
- Fix the upstream redirect configuration to reduce hop count or break the loop.
- Ensure the upstream returns the image directly (200) instead of redirecting.
- Cache the optimized result so the redirect chain is only walked once.
Example fix
# before: url redirects through many hops until count hits 0 /_next/image?url=https://host.example/redirect-to-cdn # 508 # after: use the resolved final URL /_next/image?url=https://cdn.example/final-photo.jpg&w=640&q=75
Defensive patterns
Strategy: retry
Validate before calling
// Resolve final image URL (following redirects) and store it to avoid long chains
async function resolveFinalImageUrl(u: string, maxHops = 5) {
let cur = u, hops = 0
while (hops++ < maxHops) {
const r = await fetch(cur, { redirect: 'manual' })
const loc = r.headers.get('location')
if (loc && r.status >= 300 && r.status < 400) { cur = new URL(loc, cur).href; continue }
return cur
}
throw new Error('too many redirects resolving image URL')
} Prevention
- Configure remotePatterns with the final, direct CDN URL.
- Fix upstream redirect loops/multi-hop chains.
- Cache optimized results to amortize redirect resolution.
When it happens
Trigger: Upstream responds with a chain of redirects longer than 3, or a redirect loop. Each hop decrements count; when it reaches 0 the throw at line 910 fires.
Common situations: The image URL is behind a redirect chain (auth gate -> CDN -> origin). A misconfigured upstream returns redirects back to itself (loop). HTTP<->HTTPS redirects that bounce. A URL shortener plus CDN producing multiple hops.
Related errors
- "url" parameter is valid but upstream response timed out
- "url" parameter is not allowed
- Failed to fetch ${url}
- [${label}] warmup: all ${batchSize} requests failed — server
- Failed to fetch ${url}, too many retries
AI-assisted analysis of vercel/next.js@0ae8c72462 (2026-08-06).
Data as JSON: /api/errors/414b32026165ec7a.
Report an issue: GitHub.