{"record":{"id":"5117c1666ef6f306","repo":"abhigyanpatwari/GitNexus","slug":"too-many-registry-redirects","errorCode":null,"errorMessage":"Too many registry redirects","messagePattern":"Too many registry redirects","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"gitnexus/src/core/update-check.ts","lineNumber":186,"sourceCode":"function sanitizedHttpUrl(input: string | URL, base?: string): URL {\n  const parsed = new URL(input, base);\n  parsed.username = '';\n  parsed.password = '';\n  validateGitUrl(parsed.toString());\n  return parsed;\n}\n\nasync function fetchLatest(packageUrl: string): Promise<string> {\n  let url = sanitizedHttpUrl(packageUrl);\n  for (let redirects = 0; ; redirects += 1) {\n    const response = await fetch(url.toString(), {\n      method: 'GET',\n      redirect: 'manual',\n      headers: { accept: 'application/json' },\n      signal: AbortSignal.timeout(FETCH_TIMEOUT_MS),\n    });\n    if (response.status >= 300 && response.status < 400) {\n      if (redirects >= MAX_REDIRECTS) throw new Error('Too many registry redirects');\n      const location = response.headers.get('location');\n      await response.body?.cancel().catch(() => {});\n      if (!location) throw new Error('Registry redirect missing location');\n      url = sanitizedHttpUrl(location, url.toString());\n      continue;\n    }\n    if (!response.ok) {\n      await response.body?.cancel().catch(() => {});\n      throw new Error(`Registry returned ${response.status}`);\n    }\n    const parsed = JSON.parse(await readResponseBody(response)) as {\n      version?: unknown;\n      'dist-tags'?: { latest?: unknown };\n    };\n    const latest =\n      (typeof parsed.version === 'string' ? parsed.version : undefined) ??\n      (typeof parsed['dist-tags']?.latest === 'string' ? parsed['dist-tags'].latest : undefined);\n    if (typeof latest !== 'string' || !STRICT_UPDATE_VERSION.test(latest)) {","sourceCodeStart":168,"sourceCodeEnd":204,"githubUrl":"https://github.com/abhigyanpatwari/GitNexus/blob/0d1aed942f0e8b5d3bac27519fff441aceea722d/gitnexus/src/core/update-check.ts#L168-L204","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Fetch the URL manually with curl -IL to see the redirect chain and find the loop or final destination","Configure the registry URL directly at the final destination (usually the canonical https:// registry host), eliminating the chain","Fix the misbehaving mirror/proxy that is bouncing the request"],"exampleFix":"// before\nbuildUpdateRegistry('http://bit.ly/registry-mirror'); // may exhaust MAX_REDIRECTS\n// after\nbuildUpdateRegistry('https://registry.npmjs.org'); // final destination","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"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; }","preventionTips":["Configure the final registry URL directly, avoiding short-links and redirectors","Test configured URLs with curl -IL to detect loops before use","Fix mirrors that redirect to themselves"],"tags":["npm","registry","redirect","network"],"backgroundTag":"too-many-redirects","analyzedSha":"0d1aed942f0e8b5d3bac27519fff441aceea722d","analyzedAt":"2026-09-08T00:40:44.970Z","contentChangedAt":"2026-09-08T00:40:44.970Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}