paperclipai/paperclip · error · RequestFailure

request_failed

request_failed

Error message

request_failed

What it means

The Discord request helper's catch-all converts any non-RequestFailure error (network failure, abort, fetch rejection) into RequestFailure("request_failed"), and non-ok responses (including 429 with a parsed retry_after) throw RequestFailure("request_failed", retry). It signals the Discord API call itself failed, carrying an optional retry delay for rate limits.

Source

Thrown at server/src/services/chat-discord-command-registration.ts:391

    try {
      body = JSON.parse(Buffer.concat(chunks).toString("utf8"));
    } catch {
      throw new RequestFailure("invalid_response");
    }
    if (!response.ok) {
      const value =
        body && typeof body === "object"
          ? (body as { retry_after?: unknown }).retry_after
          : undefined;
      const retry =
        response.status === 429 &&
        typeof value === "number" &&
        Number.isFinite(value) &&
        value >= 0 &&
        value <= Number.MAX_SAFE_INTEGER
          ? value
          : undefined;
      throw new RequestFailure("request_failed", retry);
    }
    return body;
  } catch (error) {
    throw error instanceof RequestFailure
      ? error
      : new RequestFailure("request_failed");
  } finally {
    void reader?.cancel().catch(() => undefined);
  }
}

/**
 * Requires a current verified bot identity and caller-owned, app-scoped lease.
 * Discord POST is an UPSERT, not create-if-absent. The preflight GET prevents
 * known collisions but cannot fence a concurrent external administrator.
 * The public marker plus the independently persisted descriptor establishes
 * reconciliation identity; the marker alone never grants command ownership.
 * Unknown writes remain attempted until GET shows the exact expected command.

View on GitHub (pinned to 01ad858492)

Solutions

  1. For 429: wait for the retry_after seconds carried by the error and retry (the reconcile loop honors it).
  2. For 401: regenerate/reset the bot token and update the stored credential.
  3. For 403/404: confirm the bot is a guild member with applications.commands scope and that applicationId/guildId match the verified identity.
  4. Check host networking (DNS, egress, TLS) if there is no HTTP status at all.

Example fix

// before
await fetch(url, { headers: { authorization: `Bot ${staleToken}` } });
// after: refresh token before calling, and honor retry
if (failure.code === "request_failed" && failure.retryAfter)
  await sleep(failure.retryAfter * 1000);
Defensive patterns

Strategy: retry

Validate before calling

const res = await fetch(url, { headers: { authorization: `Bot ${token}` } });
if (res.status === 401) throw new Error("Discord bot token invalid or expired");
if (res.status === 403 || res.status === 404) throw new Error("bot missing from guild or wrong application/guild id");

Try / catch

try { await reconcileDiscordCommandRegistration(input); }
catch (e) {
  if (e instanceof RequestFailure && e.code === "request_failed" && typeof e.retryAfter === "number") {
    await sleep(e.retryAfter * 1000); return retry();
  }
  throw e;
}

Prevention

When it happens

Trigger: Discord returns a non-2xx status (401 bad bot token, 403 missing scopes/permissions, 404 wrong application/guild id, 429 rate limit); or fetch throws (DNS failure, TLS error, connection refused, abort signal fired).

Common situations: Expired or regenerated bot token after the bot was reset in the Developer Portal; bot not added to the guild (403) or missing applications.commands scope; exceeding Discord rate limits (429, retry_after honored); network outage on the host.

Understand the failure class

Background: "API error: {status}" and "HTTP 401/403/404/429/5xx" errors: non-2xx HTTP responses explained — this error's family across 27 libraries.

Related errors


AI-assisted analysis of paperclipai/paperclip@01ad858492 (2026-09-10). Data as JSON: /api/errors/7cf8c240e8f1b1f9. Report an issue: GitHub.