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
- Retry the request — this is typically transient; add exponential backoff
- Log response.status and a snippet of the raw body text (via response.text()) to identify whether a proxy is interposing
- Check Discord's status page / network path if failures cluster in time
- 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
- Retry transient Discord REST calls with exponential backoff
- Log status code and raw body (via response.text()) when JSON parsing fails
- Check Discord status page and proxy/CDN behavior during outage clusters
- Set request timeouts so partial responses fail fast and can be retried
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
- request_failed
- Anthropic Managed Agents request failed with HTTP ${response
- OpenCode event stream returned HTTP ${response.status}
- OpenCode API ${path} request failed: ${redact(String(error),
- Discord ${operation} failed (HTTP ${response.status}${code ?
AI-assisted analysis of paperclipai/paperclip@01ad858492 (2026-09-10).
Data as JSON: /api/errors/d774599665fabeb9.
Report an issue: GitHub.