koala73/worldmonitor · error · Error
Revoke failed (HTTP ${resp.status}).
Error message
Revoke failed (HTTP ${resp.status}). What it means
Catch-all thrown by revokeMcpClient() in src/services/mcp-clients.ts for any response status outside {200, 404, 409, 401, 503}. The status is embedded in the message, so the number identifies the branch: 400 means missing/empty tokenId or invalid JSON body, 405 means a non-POST reached the route, 429 is edge rate limiting, and other 5xx are platform-level failures of the /api/user/mcp-revoke handler itself rather than the typed Convex outcomes.
Source
Thrown at src/services/mcp-clients.ts:102
},
body: JSON.stringify({ tokenId }),
});
if (resp.ok) return;
if (resp.status === 404) {
throw new Error('This client was already revoked or no longer exists.');
}
if (resp.status === 409) {
throw new Error('This client was already revoked.');
}
if (resp.status === 401) {
throw new Error('Sign in to revoke MCP clients.');
}
if (resp.status === 503) {
throw new Error('Revoke service is temporarily unavailable. Try again in a moment.');
}
throw new Error(`Revoke failed (HTTP ${resp.status}).`);
}
/**
* Fetch the caller's daily Pro MCP quota usage. Returns sane defaults on
* any failure — the settings UI is informational and should never break
* because the quota counter is unreachable.
*/
export async function fetchMcpQuota(): Promise<McpQuota> {
const fallback: McpQuota = { used: 0, limit: 50, resetsAt: nextUtcMidnightIso() };
const token = await getClerkToken();
if (!token) return fallback;
try {
const resp = await fetch('/api/user/mcp-quota', {
method: 'GET',
headers: { Authorization: `Bearer ${token}` },
});View on GitHub (pinned to eeab0a219f)
Solutions
- Parse the HTTP status out of the message and branch on it — only 503-style transient causes deserve a retry.
- For 400: validate tokenId is a non-empty string before calling, and match it against the current listMcpClients() rows.
- For 429: back off and retry with exponential delay; audit what is issuing bursts of revokes.
- For anything else, capture the response body (add temporary logging in the fetch wrapper) and inspect the edge function logs for the underlying error.
Example fix
// before
await revokeMcpClient(tokenId);
// after
if (typeof tokenId !== 'string' || tokenId.length === 0) {
throw new Error('Cannot revoke: no client selected.');
}
try {
await revokeMcpClient(tokenId);
} catch (err) {
const m = err instanceof Error ? err.message.match(/HTTP (\d+)/) : null;
if (m && m[1] === '429') { /* schedule retry */ } else { throw err; }
} Defensive patterns
Strategy: try-catch
Validate before calling
if (typeof tokenId !== 'string' || tokenId.trim().length === 0) {
throw new Error('Cannot revoke: no client selected.');
}
await revokeMcpClient(tokenId); Type guard
function revokeHttpStatus(err: unknown): number | null {
const m = err instanceof Error ? err.message.match(/^Revoke failed \(HTTP (\d+)\)\.$/) : null;
return m ? Number(m[1]) : null;
} Try / catch
try {
await revokeMcpClient(tokenId);
} catch (err) {
const status = revokeHttpStatus(err);
if (status === 429) { scheduleBackoffRetry(tokenId); return; }
if (status === 400) { fixCallerPayload(); return; }
throw err; // unknown — surface with status captured for triage
} Prevention
- Always inspect the embedded status before deciding to retry — only transient codes (429/5xx) merit it.
- Validate tokenId as a non-empty string drawn from a fresh listMcpClients() result.
- Log the response body for unexpected statuses (extend the fetch wrapper) to speed triage.
When it happens
Trigger: Sending an empty or non-string tokenId (400 missing_token_id); a malformed JSON body (400 invalid_json); calling the endpoint with GET (405); Cloudflare/Vercel rate limiting (429); an unhandled exception in the edge handler producing a plain 500.
Common situations: UI bugs passing undefined tokenIds after list refreshes reordered rows; prefetchers/scanners hitting the route with GET; bursts of revoke clicks tripping rate limits; regressions in the edge handler code.
Related errors
- P0 scrape failed: HTTP ${resp.status}
- P0 search failed: HTTP ${resp.status}
- HTTP ${resp.status}
- HTTP ${resp.status}
- HTTP ${res.status}
AI-assisted analysis of koala73/worldmonitor@eeab0a219f (2026-08-21).
Data as JSON: /api/errors/a14a905230993142.
Report an issue: GitHub.