googleapis/mcp-toolbox · error
stopped after 10 redirects
Error message
stopped after 10 redirects
What it means
The HTTP source wraps its outbound client with a CheckRedirect hook that aborts any redirect chain longer than 10 hops, matching net/http's default behavior. It returns this error from the CheckRedirect callback so the client stops following redirects. This prevents infinite redirect loops and SSRF amplification.
Source
Thrown at internal/sources/http/http.go:356
return fmt.Errorf("connection to blocked IP %s denied", ip)
}
}
return nil
},
}
if r, ok := resolver.(*net.Resolver); ok {
dialer.Resolver = r
}
tr.DialContext = dialer.DialContext
client := &http.Client{
Timeout: duration,
Transport: tr,
CheckRedirect: func(req *http.Request, via []*http.Request) error {
if len(via) >= 10 {
return fmt.Errorf("stopped after 10 redirects")
}
hostname := req.URL.Hostname()
if ip := net.ParseIP(hostname); ip != nil {
if guard.IsIPBlocked(ip) {
return fmt.Errorf("redirect to blocked IP %s denied", ip)
}
return nil
}
addrs, err := resolver.LookupHost(req.Context(), hostname)
if err != nil {
return fmt.Errorf("failed to resolve redirect host %s: %w", hostname, err)
}
for _, addr := range addrs {
if ip := net.ParseIP(addr); ip != nil {
if guard.IsIPBlocked(ip) {View on GitHub (pinned to 8cc6e09de2)
Solutions
- Fix the target URL so the server resolves the content without excessive redirects (curl -IL <url> to trace).
- Fix the server-side redirect loop (e.g. missing trailing slash, bad rewrite rules, or stale cookies causing auth bounce).
- If more than 10 hops are genuinely required, raise the limit in the CheckRedirect func in internal/sources/http/http.go.
Example fix
// before
client := &http.Client{ CheckRedirect: func(req *http.Request, via []*http.Request) error {
if len(via) >= 10 { return fmt.Errorf("stopped after 10 redirects") } ... }}
// after: raise the cap if legitimately needed
if len(via) >= 20 { return fmt.Errorf("stopped after 20 redirects") } Defensive patterns
Strategy: try-catch
Validate before calling
const target = 'https://example.com/api';
const res = await fetch(target, { redirect: 'manual' });
let hops = 0, loc = res.headers.get('location');
while (loc && hops < 12) { hops++; const r = await fetch(new URL(loc, target), { redirect: 'manual' }); loc = r.headers.get('location'); }
if (hops >= 10) console.warn('target has a redirect loop; fix server before calling the tool'); Try / catch
try {
const result = await callHttpTool(url);
} catch (err) {
if (String(err).includes('stopped after 10 redirects')) {
console.error('Redirect loop at target; inspect with curl -IL', url);
} else throw err;
} Prevention
- Trace redirect chains with curl -IL before wiring a URL into the tool config.
- Avoid pointing tools at URLs known to bounce auth (drop cookies on 3xx).
- Monitor for repeated redirect errors from one host — a sign of a server-side loop.
When it happens
Trigger: Any http.Client request via this source whose server responds with a chain of more than 10 consecutive 3xx redirects (Location headers), e.g. a redirect loop between two URLs.
Common situations: Misconfigured target server with a self-redirect loop; HTTP-to-HTTPS-to-HTTP ping-pong; auth pages that keep redirecting when cookies are dropped.
Related errors
- failed to fetch OIDC config: %w
- failed to read introspection response: %w
- failed to read response body: %w
- failed to execute request: %w
- error performing request: %w
AI-assisted analysis of googleapis/mcp-toolbox@8cc6e09de2 (2026-09-05).
Data as JSON: /api/errors/fa49538024c42bb9.
Report an issue: GitHub.