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
- 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
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
- 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
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
- Registry response too large
- Registry redirect missing location
- Registry returned ${response.status}
- Unsupported npm registry protocol
- Registry URL cannot contain query or fragment
AI-assisted analysis of abhigyanpatwari/GitNexus@0d1aed942f (2026-09-08).
Data as JSON: /api/errors/5117c1666ef6f306.
Report an issue: GitHub.