koala73/worldmonitor · error · Error

Revoke service is temporarily unavailable. Try again in a mo

Error message

Revoke service is temporarily unavailable. Try again in a moment.

What it means

Mapped by revokeMcpClient() in src/services/mcp-clients.ts from an HTTP 503 returned by POST /api/user/mcp-revoke. The edge handler's callConvexRevoke() reports 'network' — and the handler answers 503 with Retry-After: 5 — when CONVEX_SITE_URL or CONVEX_SERVER_SHARED_SECRET is unset in the edge environment, when the server-to-server fetch to Convex's internal-revoke action aborts at the 3 s timeout, on transport errors, or when Convex itself returns 5xx. Crucially the revoke did NOT land, so a retry is safe.

Source

Thrown at src/services/mcp-clients.ts:100

      'Content-Type': 'application/json',
      Authorization: `Bearer ${token}`,
    },
    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',

View on GitHub (pinned to eeab0a219f)

Solutions

  1. Retry after the advertised Retry-After (~5 s) — this status explicitly means the revoke did not execute.
  2. If it fails consistently, check the edge deployment defines CONVEX_SITE_URL and CONVEX_SERVER_SHARED_SECRET.
  3. Check the Convex status page / dashboard for deployment health during the window.
  4. Correlate with '[mcp-revoke] Convex fetch failed:' console logs from the edge to see the underlying transport error.

Example fix

// before
await revokeMcpClient(tokenId);

// after
async function revokeWithRetry(tokenId: string) {
  for (let attempt = 0; attempt < 3; attempt++) {
    try {
      return await revokeMcpClient(tokenId);
    } catch (err) {
      if (err instanceof Error && err.message.includes('temporarily unavailable') && attempt < 2) {
        await new Promise((r) => setTimeout(r, 5000));
        continue;
      }
      throw err;
    }
  }
}
Defensive patterns

Strategy: retry

Type guard

function isTransientRevokeFailure(err: unknown): boolean {
  return err instanceof Error && err.message === 'Revoke service is temporarily unavailable. Try again in a moment.';
}

Try / catch

for (let attempt = 0; ; attempt++) {
  try {
    return await revokeMcpClient(tokenId);
  } catch (err) {
    if (isTransientRevokeFailure(err) && attempt < 2) {
      await delay(5_000); // honor Retry-After: the revoke did NOT land
      continue;
    }
    throw err;
  }
}

Prevention

When it happens

Trigger: Edge deployment missing CONVEX_SITE_URL/CONVEX_SERVER_SHARED_SECRET env vars; Convex slow or degraded so the 3 s AbortSignal.timeout fires; transient network failure between the edge runtime and Convex; a Convex outage returning 5xx.

Common situations: New environments (preview/staging) where the internal Convex env vars were never added; Convex incidents; cold-start latency spikes on the edge; DNS/connectivity blips between Cloudflare edge and Convex.

Related errors


AI-assisted analysis of koala73/worldmonitor@eeab0a219f (2026-08-21). Data as JSON: /api/errors/2bf370e90276d6a5. Report an issue: GitHub.