hcengineering/platform · error · LinkPreviewError
Too many redirects
Error message
Too many redirects
What it means
LinkPreviewError thrown by fetchWithValidatedRedirects when a URL exceeds the allowed number of HTTP redirects. The library follows Location headers in a loop with a hard cap to prevent infinite redirect chains; exceeding the cap aborts with this error rather than looping forever.
Source
Thrown at pods/link-preview/src/parse.ts:268
redirect: 'manual'
},
timeoutMs
)
if (!isRedirectStatus(response.status)) {
return { response, finalUrl: currentUrl }
}
const location = response.headers.get('location')
if (!isNonEmptyString(location)) {
return { response, finalUrl: currentUrl }
}
const nextUrl = new URL(location, currentUrl).href
currentUrl = nextUrl
}
throw new LinkPreviewError('Too many redirects')
}
// ============================================================================
// Fetch Utilities
// ============================================================================
async function fetchWithTimeout (url: string, options: RequestInit, timeoutMs: number): Promise<Response> {
const controller = new AbortController()
const timeoutId = setTimeout(() => {
controller.abort()
}, timeoutMs)
try {
const response = await fetch(url, {
...options,
signal: controller.signal
})
return responseView on GitHub (pinned to 63e28dc964)
Solutions
- Test the URL with curl -IL to inspect the redirect chain and confirm whether it loops or is merely long
- Fix the server/proxy redirect loop (e.g. correct X-Forwarded-Proto handling) if you control the target
- Use the final resolved URL (pre-resolve shorteners) so fewer hops remain
- Increase the redirect limit if the library exposes configuration, or catch LinkPreviewError and skip the URL
- Verify the URL scheme: http->https upgrade loops indicate mixed-content proxy misconfig
Example fix
// before
await fetchWithValidatedRedirects('http://example.com/start')
// after
try {
const { response, finalUrl } = await fetchWithValidatedRedirects(inputUrl)
} catch (e) {
if (e instanceof LinkPreviewError) {
// skip or pre-resolve finalUrl; mark URL as unreachable
return null
}
throw e
} Defensive patterns
Strategy: try-catch
Validate before calling
function looksRedirectLoopSafe(url: string): boolean {
try { const u = new URL(url); return u.protocol === 'http:' || u.protocol === 'https:' } catch { return false }
} Type guard
function isLinkPreviewError(e: unknown): e is LinkPreviewError {
return e instanceof LinkPreviewError
} Try / catch
try {
const { response, finalUrl } = await fetchWithValidatedRedirects(url)
} catch (e) {
if (e instanceof LinkPreviewError && e.message === 'Too many redirects') {
return null // skip unreachable URL
}
throw e
} Prevention
- Pre-resolve shortener URLs before previewing
- Check suspicious URLs with curl -IL for redirect loops
- Skip URLs flagged with prior redirect failures
- Keep a redirect-hop budget when crawling
When it happens
Trigger: Calling the link preview fetch (via response) against a URL whose redirect chain is longer than the library's max, or URLs that redirect in a loop (A->B->A), or misconfigured servers emitting perpetual 301/302 responses.
Common situations: Sites with redirect loops caused by misconfigured reverse proxies (e.g. HTTPS redirect fighting with a load balancer), cookie-gated pages bouncing between endpoints, tracking URLs chained through many shorteners, or redirects pointing back to the same host with different casing/schemes that never resolve.
Related errors
- response.statusText
- Failed to fetch config
- unknownError(response.statusText)
- Failed to delete file
- Failed to delete file
AI-assisted analysis of hcengineering/platform@63e28dc964 (2026-08-29).
Data as JSON: /api/errors/3a82dac06b88a823.
Report an issue: GitHub.