ruvnet/ruflo · error · Error
HTTP transport failed: ${String(firstError instanceof Error
Error message
HTTP transport failed: ${String(firstError instanceof Error ? firstError.message : firstError)}; SSE fallback failed: ${String(err instanceof Error ? err.message : err)} What it means
Thrown by getClient when the StreamableHTTP transport failed with a recoverable error (network, 408, or transport mismatch - i.e. shouldSkipSseFallback returned false), the SSE fallback was attempted, and SSE also failed with a non-429 status. The combined Error concatenates both transport error messages and attaches the SSE error as cause. effectiveStatus, if defined, is recorded as a cooldown.
Source
Thrown at ruflo/src/ruvocal/src/lib/server/mcp/clientPool.ts:208
recordFailure(key, 429, err);
throw new McpRateLimitedError(
server.name,
429,
retryAfterMs,
err instanceof Error ? err.message : String(err)
);
}
if (effectiveStatus !== undefined) {
recordFailure(key, effectiveStatus, err);
}
const message =
"HTTP transport failed: " +
String(firstError instanceof Error ? firstError.message : firstError) +
"; SSE fallback failed: " +
String(err instanceof Error ? err.message : err);
throw new Error(message, { cause: err instanceof Error ? err : undefined });
}
}
pool.set(key, client);
return client;
}
export async function drainPool() {
for (const [key, client] of pool) {
try {
await client.close?.();
} catch {}
pool.delete(key);
}
failureCooldown.clear();
}
export function evictFromPool(server: McpServerConfig): Client | undefined {View on GitHub (pinned to 6b01dc5a68)
Solutions
- Read both halves of the message to localize the failure: 'HTTP transport failed: X; SSE fallback failed: Y'.
- Verify network reachability and scheme from the chat-ui host: curl -i the MCP URL.
- If the server only supports one transport, pin that transport or remove the redundant fallback path.
- Inspect err.cause (the SSE error) for SDK-specific details such as certificate or DNS errors.
Example fix
// before
const client = await getClient({ url: 'http://localhost:9999/mcp', name: 'svc' });
// after
try {
const client = await getClient({ url: MCP_URL, name: 'svc' });
} catch (e) {
if (e instanceof Error && e.message.startsWith('HTTP transport failed')) {
logger.error({ url: MCP_URL, err: e.message, cause: String(e.cause) }, 'MCP connect failed');
}
throw e;
} Defensive patterns
Strategy: try-catch
Validate before calling
import { isURLLocal } from "$lib/server/isURLLocal";
async function preflightMcpUrl(url: string) {
let u: URL;
try { u = new URL(url); } catch { return { ok: false, reason: "bad-url" }; }
// basic reachability hint without consuming quota
return { ok: true, host: u.host, scheme: u.protocol };
} Type guard
function isDualTransportFailure(e: unknown): e is Error {
return e instanceof Error && e.message.startsWith("HTTP transport failed");
} Try / catch
try { const client = await getClient(server); }
catch (e) {
if (e instanceof Error && e.message.startsWith("HTTP transport failed")) {
logger.error({ url: server.url, msg: e.message, cause: String((e as Error & { cause?: unknown }).cause) }, "MCP unreachable");
return { reachable: false };
}
throw e;
} Prevention
- Verify network reachability from the chat-ui host (curl -i the MCP URL) before wiring it into MCP_SERVERS.
- Match the URL scheme to what the server implements (https for StreamableHTTP, http(s) for SSE).
- Inspect err.cause for SDK-level detail (DNS, TLS, connection refused).
- Avoid routing MCP traffic through proxies that block SSE long-polling.
When it happens
Trigger: Network unreachable to the MCP server host; wrong scheme (http vs https); self-signed cert; server only supports StreamableHTTP but the request triggered a transport mismatch that then failed over SSE which also errored; DNS resolution failure; timeout on both transports; proxy/firewall blocking both paths.
Common situations: Local dev with misconfigured MCP URL (e.g. wrong port); corporate proxy blocking SSE; MCP server that only implements the new StreamableHTTP transport returning an SSE-specific error on fallback; TLS/cert problems; containerized deployments where the MCP host is unreachable from the chat-ui pod.
Related errors
- MCP server "${server.name}" returned HTTP ${httpStatus}: ${h
- MCP server "${server.name}" is in cooldown (HTTP ${cd.status
- Failed to fetch ${baseURL}/models: ${response.status} ${resp
- Failed to fetch base servers: ${response.statusText}
- browser/eval: script exceeds maximum length of ${MAX_EVAL_SC
AI-assisted analysis of ruvnet/ruflo@6b01dc5a68 (2026-08-12).
Data as JSON: /api/errors/3d641302317e6336.
Report an issue: GitHub.