koala73/worldmonitor · error · Error
HTTP ${resp.status}
Error message
HTTP ${resp.status} What it means
Thrown by McpDataPanel when invoking a remote MCP tool via POST /api/mcp-proxy fails: the JSON body carries { serverUrl, toolName, toolArgs, customHeaders }, and on failure the message is data.error from the proxy response (remote tool error, unknown tool, argument validation failure at the MCP server) or the literal 'HTTP <status>' when the body carries no error field. The signal is AbortSignal.any([destroyController, timeout(20s)]), so panel destruction aborts instead of throwing this.
Source
Thrown at src/components/McpDataPanel.ts:118
this.showLoading();
try {
// premiumFetch attaches the Clerk Pro Bearer for normal web Pro
// users. /api/mcp-proxy is in PREMIUM_RPC_PATHS so the path gate
// fires; the server-side isCallerPremium check accepts Bearer,
// wm_ user keys, and enterprise keys (PR #3768).
const resp = await premiumFetch(proxyUrl('/api/mcp-proxy'), {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
serverUrl: this.spec.serverUrl,
toolName: this.spec.toolName,
toolArgs: this.spec.toolArgs,
customHeaders: this.spec.customHeaders,
}),
signal: AbortSignal.any([this.destroyController.signal, AbortSignal.timeout(20_000)]),
});
const data = await resp.json() as { result?: McpResult; error?: string };
if (!resp.ok || data.error) throw new Error(data.error || `HTTP ${resp.status}`);
this.lastFetchedAt = Date.now();
this.renderResult(data.result ?? {});
} catch (err) {
const msg = err instanceof Error ? err.message : String(err);
this.showError(msg);
}
}
private renderResult(result: McpResult): void {
const jsonData = this.extractJsonData(result);
if (jsonData !== null && isProWidgetEnabled()) {
const hash = JSON.stringify(jsonData).slice(0, 8192);
if (hash === this.lastJsonHash && this.cachedWidgetHtml) {
this.setSafeContent(unsafeRawHtml(`
<div class="mcp-panel-meta">${this.buildMetaLine()}</div>
<div class="mcp-panel-content mcp-panel-widget">${wrapProWidgetHtml(this.cachedWidgetHtml)}</div>
`, 'legacy Panel.setContent() migration'));View on GitHub (pinned to eeab0a219f)
Solutions
- Validate toolName and toolArgs against the tools list returned at connect time before invoking; re-connect to refresh it
- Read data.error first — it is the remote MCP server's own error text and names the real cause (unknown tool vs auth vs crash)
- Re-run connect to confirm the server is still reachable and the user's premium auth still passes the proxy gate
- Persist server credentials with the spec so customHeaders survive reloads instead of silently degrading to 401
Example fix
// before
const data = await resp.json();
if (!resp.ok || data.error) throw new Error(data.error || `HTTP ${resp.status}`);
// after (gate the call on the connected tool inventory):
if (!this.knownTools?.some(t => t.name === this.spec.toolName)) {
this.showError(`Unknown tool: ${this.spec.toolName}`); // fail before the network round-trip
return;
}
const data = await resp.json();
if (!resp.ok || data.error) throw new Error(data.error || `HTTP ${resp.status}`); Defensive patterns
Strategy: try-catch
Validate before calling
const known = this.knownTools?.map(t => t.name) ?? [];
if (!known.includes(this.spec.toolName)) { this.showError(`Unknown tool: ${this.spec.toolName}`); return; } Type guard
function isKnownTool(spec: { toolName: string }, known: { name: string }[]): boolean { return known.some(t => t.name === spec.toolName); } Try / catch
catch (err) { const msg = err instanceof Error ? err.message : String(err); if (/^HTTP \d+$/.test(msg)) { handleProxyStatus(Number(msg.slice(5))); } else { showError(msg); // data.error: remote MCP server's own message — show verbatim } } Prevention
- Re-connect to refresh the tool inventory before invoking stored widget specs
- Persist customHeaders with the spec so auth survives reloads
- Abort on destroy (the panel already unions the destroy signal) so teardown never surfaces as this error
When it happens
Trigger: Calling a tool whose server went down after connect (data.error); passing toolName/toolArgs the server rejects — unknown tool or schema-invalid arguments (data.error); losing Pro auth between connect and invoke (401/403, HTTP path); proxy 5xx. Slow tools exceeding 20s abort with TimeoutError instead — this message means a completed HTTP exchange with a bad outcome.
Common situations: Dashboard configs persisting a widget spec whose MCP server credentials expired; toolArgs exported from a different server version (schema drift); panel kept alive across sessions where the stored serverUrl rotted.
Related errors
- HTTP ${resp.status}
- HTTP ${res.status}
- HTTP ${resp.status}
- Brief service unavailable (${res.status})
- Revoke failed (HTTP ${resp.status}).
AI-assisted analysis of koala73/worldmonitor@eeab0a219f (2026-08-21).
Data as JSON: /api/errors/6d47ddfb23adc52b.
Report an issue: GitHub.