vercel/ai · error · DownloadError

Too many redirects (max ${maxRedirects})

Error message

Too many redirects (max ${maxRedirects})

What it means

fetchWithValidatedRedirects caps redirect chains at maxRedirects (default 10) to prevent infinite redirect loops that would exhaust connections or enable DoS. When the chain exceeds the limit, the download is aborted with this DownloadError. Redirect loops are almost always a server- or configuration-side problem, not a client bug.

Source

Thrown at packages/provider-utils/src/fetch-with-validated-redirects.ts:151

      // redirect that crosses origin. Only stripping Authorization (as the
      // fetch spec does) is not enough on the server: providers authenticate
      // with custom headers too (e.g. `x-key`), and without CORS there is
      // nothing else stopping them from riding to a foreign host.
      if (currentHeaders !== undefined && !isSameOrigin(nextUrl, currentUrl)) {
        const userAgent = currentHeaders.get('user-agent');
        currentHeaders = new Headers(
          userAgent == null ? undefined : { 'user-agent': userAgent },
        );
      }

      currentUrl = nextUrl;
      continue;
    }

    return response;
  }

  throw new DownloadError({
    url,
    message: `Too many redirects (max ${maxRedirects})`,
  });
}

View on GitHub (pinned to 69428b1f8b)

Solutions

  1. Follow the URL manually (curl -IL) to inspect the redirect chain and find where it loops.
  2. Fix the origin: correct http→https or www redirect configuration on the asset host so a single hop reaches the file.
  3. Use the final, direct asset URL instead of a redirecting short link.
  4. If the chain is legitimate but long, supply a custom fetch or raise maxRedirects where the API surface allows it.

Example fix

// before: URL bounces forever between http/https
const blob = await downloadBlob('http://cdn.example.com/video.mp4');

// after: use the final https URL directly
const blob = await downloadBlob('https://cdn.example.com/video.mp4');
Defensive patterns

Strategy: validation

Validate before calling

async function countRedirects(url: string, max = 10): Promise<number> {
  let hops = 0;
  let current = url;
  while (hops <= max) {
    const res = await fetch(current, { redirect: 'manual' });
    const location = res.headers.get('location');
    if (!(res.status >= 300 && res.status < 400) || !location) return hops;
    current = new URL(location, current).toString();
    hops++;
  }
  throw new Error(`URL exceeds ${max} redirects`);
}

Type guard

import { DownloadError } from '@ai-sdk/provider-utils';
function isTooManyRedirects(e: unknown): boolean {
  return DownloadError.isInstance(e) && e.message.startsWith('Too many redirects');
}

Try / catch

try {
  await downloadBlob(url);
} catch (error) {
  if (DownloadError.isInstance(error) && error.message.startsWith('Too many redirects')) {
    // follow chain with curl -IL, fix the looping origin or use the final URL
  }
  throw error;
}

Prevention

When it happens

Trigger: A file/media URL passed to the SDK (via downloadBlob and downstream provider calls) redirects more than 10 times, or two URLs redirect to each other in a loop (e.g. http→https→http, or with/without trailing slash misconfiguration).

Common situations: Misconfigured reverse proxy bouncing between http and https; www vs non-www redirect loops; cookie-gated URLs bouncing between login and asset; CDN misconfiguration; an auth-required URL that keeps redirecting because credentials are stripped on cross-origin hops.

Related errors


AI-assisted analysis of vercel/ai@69428b1f8b (2026-08-30). Data as JSON: /api/errors/e3d832aa9206731a. Report an issue: GitHub.