ChatGPTNextWeb/NextChat · warning · Error
Failed to load tools
Error message
Failed to load tools
What it means
Thrown at app/components/mcp-market.tsx:235 inside loadTools when getClientTools(id) returns null. getClientTools (app/mcp/actions.ts:78) returns clientsMap.get(clientId)?.tools ?? null, so null means either the clientId is absent from the in-memory clientsMap, or the entry exists but its .tools is null (init failed, paused, or still initializing).
Source
Thrown at app/components/mcp-market.tsx:235
setConfig(newConfig);
showToast("Server configuration updated successfully");
} catch (error) {
showToast(
error instanceof Error ? error.message : "Failed to save configuration",
);
} finally {
updateLoadingState(savingServerId, null);
}
};
// 获取服务器支持的 Tools
const loadTools = async (id: string) => {
try {
const result = await getClientTools(id);
if (result) {
setTools(result);
} else {
throw new Error("Failed to load tools");
}
} catch (error) {
showToast("Failed to load tools");
console.error(error);
setTools(null);
}
};
// 更新加载状态的辅助函数
const updateLoadingState = (id: string, message: string | null) => {
setLoadingStates((prev) => {
if (message === null) {
const { [id]: _, ...rest } = prev;
return rest;
}
return { ...prev, [id]: message };
});
};View on GitHub (pinned to defdcdb55d)
Solutions
- Check getClientsStatus()[id].status === 'active' before calling loadTools; if paused, call resumeMcpServer first.
- If status is 'initializing', poll or await completion before loading tools.
- If status is 'error', surface errorMsg instead of the generic 'Failed to load tools'.
- Differentiate 'no tools' from 'client missing' so the user knows whether to resume or re-add.
Example fix
// before
const result = await getClientTools(id);
if (result) {
setTools(result);
} else {
throw new Error("Failed to load tools");
}
// after
const status = (await getClientsStatus())[id];
if (!status) {
showToast(`Server ${id} not found`);
setTools(null);
return;
}
if (status.status === "paused") {
showToast(`Resume ${id} first`);
setTools(null);
return;
}
if (status.status === "error") {
showToast(`Server error: ${status.errorMsg ?? "unknown"}`);
setTools(null);
return;
}
const result = await getClientTools(id);
setTools(result ?? []); Defensive patterns
Strategy: validation
Validate before calling
import { getClientsStatus } from "@/app/mcp/actions";
async function canLoadTools(id: string): Promise<boolean> {
const statuses = await getClientsStatus();
return statuses[id]?.status === "active";
}
if (await canLoadTools(id)) {
await loadTools(id);
} else {
showToast(`Server ${id} is not active; cannot list tools`);
} Type guard
function hasTools(tools: unknown): tools is NonNullable<ReturnType<typeof getClientTools>> {
return tools != null && Array.isArray(tools);
} Try / catch
try {
const result = await getClientTools(id);
if (!result) throw new Error("Failed to load tools");
setTools(result);
} catch {
const status = (await getClientsStatus())[id];
showToast(
status?.status === "paused"
? `Resume ${id} first`
: `Server ${id} error: ${status?.errorMsg ?? "unknown"}`,
);
setTools(null);
} Prevention
- Only offer 'view tools' when getClientsStatus reports 'active'.
- Distinguish 'paused' and 'error' states so the user gets an actionable message.
- Await initialization completion before enabling tool-list actions.
When it happens
Trigger: User opens the 'tools' view for a server that is paused, in 'error' status, still initializing (tools not yet populated), or not in clientsMap at all (never added / removed / map cleared by restartAllClients).
Common situations: Clicking 'view tools' right after adding a server before async init finishes; server failed to start (bad command/path, missing env); server was paused; restartAllClients ran and the map is mid-rebuild; the id passed is stale.
Related errors
- Client ${clientId} not found
- Failed to load preset servers
- Server ${clientId} not found
- Recording not started
AI-assisted analysis of ChatGPTNextWeb/NextChat@defdcdb55d (2026-08-12).
Data as JSON: /api/errors/e1a16d372998691f.
Report an issue: GitHub.