abhigyanpatwari/GitNexus · error

Too many registry redirects

Error message

Too many registry redirects

What it means

fetchLatest follows registry redirects manually (redirect: 'manual') and re-validates each Location via sanitizedHttpUrl. When the number of redirects exceeds MAX_REDIRECTS, it throws this error instead of following further — a loop/chain guard that also bounds SSRF exposure through redirect chains.

Source

Thrown at gitnexus/src/core/update-check.ts:186

function sanitizedHttpUrl(input: string | URL, base?: string): URL {
  const parsed = new URL(input, base);
  parsed.username = '';
  parsed.password = '';
  validateGitUrl(parsed.toString());
  return parsed;
}

async function fetchLatest(packageUrl: string): Promise<string> {
  let url = sanitizedHttpUrl(packageUrl);
  for (let redirects = 0; ; redirects += 1) {
    const response = await fetch(url.toString(), {
      method: 'GET',
      redirect: 'manual',
      headers: { accept: 'application/json' },
      signal: AbortSignal.timeout(FETCH_TIMEOUT_MS),
    });
    if (response.status >= 300 && response.status < 400) {
      if (redirects >= MAX_REDIRECTS) throw new Error('Too many registry redirects');
      const location = response.headers.get('location');
      await response.body?.cancel().catch(() => {});
      if (!location) throw new Error('Registry redirect missing location');
      url = sanitizedHttpUrl(location, url.toString());
      continue;
    }
    if (!response.ok) {
      await response.body?.cancel().catch(() => {});
      throw new Error(`Registry returned ${response.status}`);
    }
    const parsed = JSON.parse(await readResponseBody(response)) as {
      version?: unknown;
      'dist-tags'?: { latest?: unknown };
    };
    const latest =
      (typeof parsed.version === 'string' ? parsed.version : undefined) ??
      (typeof parsed['dist-tags']?.latest === 'string' ? parsed['dist-tags'].latest : undefined);
    if (typeof latest !== 'string' || !STRICT_UPDATE_VERSION.test(latest)) {

View on GitHub (pinned to 0d1aed942f)

Solutions

  1. Fetch the URL manually with curl -IL to see the redirect chain and find the loop or final destination
  2. Configure the registry URL directly at the final destination (usually the canonical https:// registry host), eliminating the chain
  3. Fix the misbehaving mirror/proxy that is bouncing the request

Example fix

// before
buildUpdateRegistry('http://bit.ly/registry-mirror'); // may exhaust MAX_REDIRECTS
// after
buildUpdateRegistry('https://registry.npmjs.org'); // final destination
Defensive patterns

Strategy: try-catch

Try / catch

try { const latest = await fetchLatest(url, 0); } catch (e) { if (e.message === 'Too many registry redirects') { console.warn('Registry redirect loop detected; skipping update check'); } else throw e; }

Prevention

When it happens

Trigger: A registry endpoint (or an intermediate hop) returns 3xx on every request — a redirect loop — or an unusually long redirect chain (> MAX_REDIRECTS hops), e.g. http→https→mirror→mirror→… configured recursively.

Common situations: Misconfigured mirror whose redirect points back at itself or alternates between two URLs; cookie-less auth redirects (server keeps redirecting to a login URL that again redirects); registry URL accidentally set to a short-link that redirects many times.

Related errors


AI-assisted analysis of abhigyanpatwari/GitNexus@0d1aed942f (2026-09-08). Data as JSON: /api/errors/5117c1666ef6f306. Report an issue: GitHub.