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

  1. Read both halves of the message to localize the failure: 'HTTP transport failed: X; SSE fallback failed: Y'.
  2. Verify network reachability and scheme from the chat-ui host: curl -i the MCP URL.
  3. If the server only supports one transport, pin that transport or remove the redundant fallback path.
  4. 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

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


AI-assisted analysis of ruvnet/ruflo@6b01dc5a68 (2026-08-12). Data as JSON: /api/errors/3d641302317e6336. Report an issue: GitHub.