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 response

View on GitHub (pinned to 63e28dc964)

Solutions

  1. Test the URL with curl -IL to inspect the redirect chain and confirm whether it loops or is merely long
  2. Fix the server/proxy redirect loop (e.g. correct X-Forwarded-Proto handling) if you control the target
  3. Use the final resolved URL (pre-resolve shorteners) so fewer hops remain
  4. Increase the redirect limit if the library exposes configuration, or catch LinkPreviewError and skip the URL
  5. 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

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


AI-assisted analysis of hcengineering/platform@63e28dc964 (2026-08-29). Data as JSON: /api/errors/3a82dac06b88a823. Report an issue: GitHub.