ruvnet/ruflo · error · Error
Failed to fetch base servers: ${response.statusText}
Error message
Failed to fetch base servers: ${response.statusText} What it means
Thrown by refreshMcpServers() in the client-side Svelte store when GET ${base}/api/mcp/servers returns a non-OK HTTP status. The store merges base servers with custom servers and the WASM server, so a failed base fetch aborts the whole refresh. The error carries only response.statusText, not the body.
Source
Thrown at ruflo/src/ruvocal/src/lib/stores/mcpServers.ts:171
export const allBaseServersEnabled = derived(
[allMcpServers, selectedServerIds],
([$all, $selected]) => {
const baseServers = $all.filter((s) => s.type === "base");
return baseServers.length > 0 && baseServers.every((s) => $selected.has(s.id));
}
);
// Note: Authorization overlay (with user's HF token) for the Hugging Face MCP host
// is applied server-side when enabled via MCP_FORWARD_HF_USER_TOKEN.
/**
* Refresh base servers from API and merge with custom servers + WASM server
*/
export async function refreshMcpServers() {
try {
const response = await fetch(`${base}/api/mcp/servers`);
if (!response.ok) {
throw new Error(`Failed to fetch base servers: ${response.statusText}`);
}
const baseServers: MCPServer[] = await response.json();
const customServers = loadCustomServers();
// Create WASM server and add to the list
const wasmServer = createWasmServer();
// Merge base, custom, and WASM servers
const merged = [wasmServer, ...baseServers, ...customServers];
allMcpServers.set(merged);
// Load disabled base servers
const disabledBaseIds = loadDisabledBaseIds();
// Auto-enable all base servers that aren't explicitly disabled
// Plus keep any custom servers that were previously selected
// WASM server is auto-enabled by defaultView on GitHub (pinned to 6b01dc5a68)
Solutions
- Open ${base}/api/mcp/servers in a browser/devtools and read the actual status + body.
- Confirm the SvelteKit server is running and the backend route exists under src/routes/api/mcp/servers.
- Check server logs for the 500 that produced the statusText.
- Verify auth/session cookies if the endpoint requires a logged-in user.
- Wrap the call site in a retry with backoff for transient 5xx, and degrade to customServers + wasmServer only on persistent failure.
Example fix
// before
const response = await fetch(`${base}/api/mcp/servers`);
if (!response.ok) throw new Error(`Failed to fetch base servers: ${response.statusText}`);
// after
const response = await fetch(`${base}/api/mcp/servers`);
if (!response.ok) {
const body = await response.text().catch(() => "");
throw new Error(`Failed to fetch base servers: ${response.status} ${response.statusText} ${body}`);
} Defensive patterns
Strategy: retry
Validate before calling
async function pingMcpServers(base: string, fetchFn = fetch): Promise<boolean> {
try {
const r = await fetchFn(`${base}/api/mcp/servers`, { method: "GET" });
return r.ok;
} catch {
return false;
}
}
// before refreshMcpServers:
if (!(await pingMcpServers(base))) {
console.warn("backend /api/mcp/servers unreachable; skipping base server refresh");
} Type guard
function isMCPServerArray(x: unknown): x is MCPServer[] {
return Array.isArray(x) && x.every((s) => s && typeof s.id === "string" && typeof s.name === "string");
} Try / catch
async function refreshMcpServersSafe() {
try {
await refreshMcpServers();
} catch (e) {
console.warn("base MCP servers unavailable, continuing with custom+WASM only:", String((e as Error)?.message ?? e));
allMcpServers.set([createWasmServer(), ...loadCustomServers()]);
}
} Prevention
- Add a health-check call before the first refresh so the UI does not throw on cold start.
- Retry 5xx with exponential backoff; do not retry 4xx.
- Degrade gracefully: base servers are additive, so the store can still show custom + WASM servers when base is down.
When it happens
Trigger: The /api/mcp/servers endpoint returns 4xx/5xx (backend down, auth required, route missing), the dev server is not running, the base path is misconfigured, or a proxy/CORS preflight fails and surfaces as a non-OK response.
Common situations: Running only the client without the SvelteKit backend; OPENAI_BASE_URL / app base path wrong; backend crashed during startup so /api/mcp/servers 500s; a deploy where the API mount point changed.
Related errors
- Failed to create share link
- MCP server "${server.name}" is in cooldown (HTTP ${cd.status
- MCP server "${server.name}" returned HTTP ${httpStatus}: ${h
- HTTP transport failed: ${String(firstError instanceof Error
- Failed to fetch ${url}: ${response.status} ${response.status
AI-assisted analysis of ruvnet/ruflo@6b01dc5a68 (2026-08-12).
Data as JSON: /api/errors/f148691bf8d189af.
Report an issue: GitHub.