paperclipai/paperclip · error · Error

Discord returned an unreadable response

Error message

Discord returned an unreadable response

What it means

discordJson() wraps Discord REST calls and parses the response body as JSON. This error is thrown when response.json() rejects — the body is not valid JSON (empty body, HTML error page, truncated response). It is a guarded parse failure raised before HTTP status is checked.

Source

Thrown at server/src/services/chat-discord.ts:135

    return 0n;
  }
}

async function discordJson<T>(
  fetchImpl: typeof globalThis.fetch,
  token: string,
  path: string,
  operation: string,
): Promise<T> {
  const response = await fetchImpl(`${DISCORD_API_URL}${path}`, {
    signal: requestSignal(),
    headers: { authorization: `Bot ${token}` },
  });
  let body: unknown;
  try {
    body = await response.json();
  } catch {
    throw new Error("Discord returned an unreadable response");
  }
  if (!response.ok) {
    const errorBody =
      body && typeof body === "object" ? (body as DiscordErrorBody) : null;
    const codeValue = String(errorBody?.code ?? "");
    const code = /^\d{1,10}$/.test(codeValue) ? codeValue : null;
    const invalidFields =
      errorBody?.errors && typeof errorBody.errors === "object"
        ? Object.keys(errorBody.errors)
            .filter((field) => SAFE_DISCORD_ERROR_FIELDS.has(field))
            .slice(0, 8)
        : [];
    throw new Error(
      `Discord ${operation} failed (HTTP ${response.status}${code ? `, code ${code}` : ""}${invalidFields.length > 0 ? `, invalid fields: ${invalidFields.join(", ")}` : ""})`,
    );
  }
  return body as T;
}

View on GitHub (pinned to 01ad858492)

Solutions

  1. Retry the request — this is typically transient; add exponential backoff
  2. Log response.status and a snippet of the raw body text (via response.text()) to identify whether a proxy is interposing
  3. Check Discord's status page / network path if failures cluster in time
  4. Consider parsing with response.text() then JSON.parse so the raw body can be included in diagnostics

Example fix

// before
try { body = await response.json(); } catch { throw new Error("Discord returned an unreadable response"); }
// after
const raw = await response.text();
try { body = JSON.parse(raw); } catch { throw new Error(`Discord returned an unreadable response: ${raw.slice(0, 200)}`); }
Defensive patterns

Strategy: try-catch

Try / catch

try {
  await verifyDiscordBot(input);
} catch (err) {
  if (err.message === "Discord returned an unreadable response") {
    // transient: retry with backoff, log raw body for diagnostics
    await sleep(backoff(attempt));
    return retry();
  }
  throw err;
}

Prevention

When it happens

Trigger: Discord (or an intermediary proxy/CDN) returns an empty body or an HTML/CDN error page for a Bot-token API request; the connection is interrupted mid-body; a network appliance rewrites the response.

Common situations: Cloudflare or corporate proxy returning an HTML 502/521 page during Discord outages; rate-limit responses with empty bodies; transient network failures dropping the response mid-stream.

Understand the failure class

Background: "Invalid JSON response" and "Failed to parse response" errors: when an API answers 200 but the body isn't the JSON your library expected — this error's family across 28 libraries.

Related errors


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