koala73/worldmonitor · error

${label} HTTP ${response.status}

Error message

${label} HTTP ${response.status}

What it means

This is the generic non-ok fallback of assertToolFetchOk in api/mcp/billing-denial.ts: the tool's gateway fetch returned a non-ok status that is neither a billing denial (no X-Billing-Verification marker header with a known code) nor a 400 carrying safe proto violations. The message preserves the '<label> HTTP <status>' contract that dispatch's catch-all and log-severity downgrade key on. Every other classification (BillingDenialError, RpcValidationError) has already been ruled out by the time this throws.

Source

Thrown at api/mcp/billing-denial.ts:185

 * Standard non-ok handling for tool `_execute` gateway fetches: billing
 * denials become typed errors dispatch can re-emit faithfully; proto 400
 * bodies with safe field violations become RpcValidationError; everything
 * else keeps the existing `<label> HTTP <status>` Error contract.
 *
 * HTTP 400 response bodies are consumed only to classify violations. Callers
 * must await this helper — a forgotten await would let execution continue
 * and treat the 400 as success.
 */
export async function assertToolFetchOk(response: ToolFetchResponse, label: string): Promise<void> {
  if (response.ok) return;
  throwIfBillingDenial(response, label);
  if (response.status === 400) {
    const violations = await extractSafeRpcViolations(response);
    if (violations.length > 0) {
      throw new RpcValidationError(label, violations);
    }
  }
  throw new Error(`${label} HTTP ${response.status}`);
}

View on GitHub (pinned to eeab0a219f)

Solutions

  1. Parse the status from the message (/ HTTP (\d+)$/) — 401/403 means auth/entitlement, 404 means route drift, 5xx means retry later
  2. For 401/403, verify the auth headers: method, full path with query string, and body must match exactly what buildAuthHeaders signed
  3. For 404, confirm the route named in the label exists in the target deployment (check docs/api/ OpenAPI or hit the path directly)
  4. For 5xx/429, retry with backoff honoring any Retry-After header
Defensive patterns

Strategy: try-catch

Type guard

function isToolHttpError(e) {
  return e instanceof Error && / HTTP \d+$/.test(e.message)
    && !(e instanceof RpcValidationError) && e.name !== 'BillingDenialError';
}
function httpStatusOf(e) { const m = e.message.match(/HTTP (\d+)$/); return m ? Number(m[1]) : null; }

Try / catch

try {
  const r = await client.callTool(name, args);
} catch (e) {
  if (isToolHttpError(e)) {
    const s = httpStatusOf(e);
    if (s >= 500 || s === 429) return retryWithBackoff(() => client.callTool(name, args), 3);
    if (s === 401 || s === 403) throw new Error('Auth/entitlement failure — refresh credentials', { cause: e });
    throw e; // 4xx other than 401/403: not retryable
  }
  throw e;
}

Prevention

When it happens

Trigger: Any tools/call whose _execute fetches a /api/... route and gets 401/403/404/409/429/500/502/503 back: an expired or mis-signed HMAC auth header (401), a lapsed entitlement without the billing marker (403), a route that does not exist in this deployment (404), or an upstream 5xx. Also fires for 400s whose body is HTML, malformed JSON, or has no sanitizable violations array.

Common situations: Signature canonicalization drift between buildAuthHeaders and the gateway (method, path, or body hash mismatch). Deploying the MCP registry and the API routes out of sync so a tool POSTs to a path that is not yet deployed. Upstream dependency outage surfacing as 502/503. Env var misconfiguration (wrong secret) producing consistent 401s.

Related errors


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