mastra-ai/mastra · error · MastraError
MCP_CLIENT_TOO_MANY_REDIRECTS
MCP_CLIENT_TOO_MANY_REDIRECTS
Error message
Exceeded the maximum of ${MAX_REDIRECT_HOPS} redirect hops while requesting host "${currentUrl.host}" under the allowedHosts policy. What it means
To prevent infinite redirect loops, fetchFollowingAllowedRedirects caps the number of hops at MAX_REDIRECT_HOPS. Exceeding the cap throws MCP_CLIENT_TOO_MANY_REDIRECTS (THIRD_PARTY), and the message deliberately interpolates only the host (not the full URL) so the error is not misclassified as transient by isReconnectableMCPError.
Source
Thrown at packages/mcp/src/client/url-policy.ts:213
const headers = new Headers(init?.headers);
for (let redirectsFollowed = 0; ; redirectsFollowed++) {
const response = await fetchImpl(currentUrl, { ...init, method, body, headers, redirect: 'manual' });
if (!REDIRECT_STATUS_CODES.has(response.status)) {
return response;
}
const location = response.headers.get('location');
if (!location) {
throw new MastraError({
id: 'MCP_CLIENT_REDIRECT_MISSING_LOCATION',
domain: ErrorDomain.MCP,
category: ErrorCategory.THIRD_PARTY,
text: `Received a ${response.status} redirect with no Location header from "${currentUrl.host}" while following redirects under the allowedHosts policy.`,
});
}
if (redirectsFollowed >= MAX_REDIRECT_HOPS) {
throw new MastraError({
id: 'MCP_CLIENT_TOO_MANY_REDIRECTS',
domain: ErrorDomain.MCP,
category: ErrorCategory.THIRD_PARTY,
// Interpolate only the host, not the full URL: a URL's path/query could
// contain substrings (e.g. "sessionId") that isReconnectableMCPError
// matches, which would misclassify this terminal failure as transient.
text: `Exceeded the maximum of ${MAX_REDIRECT_HOPS} redirect hops while requesting host "${currentUrl.host}" under the allowedHosts policy.`,
});
}
// Release the redirect response's body so its socket can be reused.
cancelResponseBody(response);
const nextUrl = new URL(location, currentUrl);
assertHostAllowed(nextUrl, allowedHosts, `A redirect from "${currentUrl.host}" pointed at it; the hop was not followed.`);
const methodUpper = method.toUpperCase();
const dropsBody =View on GitHub (pinned to 75dd419e61)
Solutions
- Trace the redirect chain with curl -IL and break the loop in server/gateway config
- Call the final URL directly to avoid the redirect chain
- Add all loop endpoints consistently to allowedHosts or restructure the deployment so the loop disappears
- Increase hops only if the chain is legitimately long (rare; prefer fixing the loop)
Example fix
// before (gateway misconfig loop) /app -> redirect /app/ -> redirect /app (loop) // after serve /app directly, or a single 308 redirect /app -> /app/ with no further redirect
Defensive patterns
Strategy: fallback
Validate before calling
let url = startUrl; let hops = 0;
while (REDIRECT_STATUS_CODES.has((await fetch(url, { redirect: 'manual' })).status)) {
if (++hops > 5) throw new Error(`Redirect loop detected starting at ${startUrl}`);
url = new URL((await fetch(url, { redirect: 'manual' })).headers.get('location'), url);
} Type guard
null
Try / catch
try {
await client.tools();
} catch (e) {
if (e instanceof MastraError && e.id === 'MCP_CLIENT_TOO_MANY_REDIRECTS') {
// Do NOT retry: terminal error; message deliberately non-transient
console.error(`Redirect loop at host '${extractHost(e)}'; fix gateway config or call final URL directly`);
} else throw e;
} Prevention
- Trace redirect chains with curl -IL before wiring clients
- Eliminate gateway/ingress rewrite loops (trailing-slash, auth bounce)
- Keep allowedHosts consistent across the whole chain
When it happens
Trigger: A chain of redirects between allowed hosts that loops (A→B→A) or is longer than MAX_REDIRECT_HOPS while using the allowedHosts policy.
Common situations: Misconfigured gateway ping-ponging between two URLs; auth redirects bouncing between login and resource URLs; proxy rewrite loops in Kubernetes ingress or API gateways.
Related errors
- MCP_CLIENT_REDIRECT_MISSING_LOCATION
- Failed to fetch prompts from server ${this.client.name}: ${e
- Failed to fetch resources from server ${this.client.name}: $
- Failed to fetch resource templates from server ${this.client
- Could not connect to server with any available HTTP transpor
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/3cbc2b47aca3c939.
Report an issue: GitHub.