{"record":{"id":"d774599665fabeb9","repo":"paperclipai/paperclip","slug":"discord-returned-an-unreadable-response","errorCode":null,"errorMessage":"Discord returned an unreadable response","messagePattern":"Discord returned an unreadable response","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"server/src/services/chat-discord.ts","lineNumber":135,"sourceCode":"    return 0n;\n  }\n}\n\nasync function discordJson<T>(\n  fetchImpl: typeof globalThis.fetch,\n  token: string,\n  path: string,\n  operation: string,\n): Promise<T> {\n  const response = await fetchImpl(`${DISCORD_API_URL}${path}`, {\n    signal: requestSignal(),\n    headers: { authorization: `Bot ${token}` },\n  });\n  let body: unknown;\n  try {\n    body = await response.json();\n  } catch {\n    throw new Error(\"Discord returned an unreadable response\");\n  }\n  if (!response.ok) {\n    const errorBody =\n      body && typeof body === \"object\" ? (body as DiscordErrorBody) : null;\n    const codeValue = String(errorBody?.code ?? \"\");\n    const code = /^\\d{1,10}$/.test(codeValue) ? codeValue : null;\n    const invalidFields =\n      errorBody?.errors && typeof errorBody.errors === \"object\"\n        ? Object.keys(errorBody.errors)\n            .filter((field) => SAFE_DISCORD_ERROR_FIELDS.has(field))\n            .slice(0, 8)\n        : [];\n    throw new Error(\n      `Discord ${operation} failed (HTTP ${response.status}${code ? `, code ${code}` : \"\"}${invalidFields.length > 0 ? `, invalid fields: ${invalidFields.join(\", \")}` : \"\"})`,\n    );\n  }\n  return body as T;\n}","sourceCodeStart":117,"sourceCodeEnd":153,"githubUrl":"https://github.com/paperclipai/paperclip/blob/01ad8584922b5d85292b1723cae71fa0d9b07a19/server/src/services/chat-discord.ts#L117-L153","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\ntry { body = await response.json(); } catch { throw new Error(\"Discord returned an unreadable response\"); }\n// after\nconst raw = await response.text();\ntry { body = JSON.parse(raw); } catch { throw new Error(`Discord returned an unreadable response: ${raw.slice(0, 200)}`); }","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  await verifyDiscordBot(input);\n} catch (err) {\n  if (err.message === \"Discord returned an unreadable response\") {\n    // transient: retry with backoff, log raw body for diagnostics\n    await sleep(backoff(attempt));\n    return retry();\n  }\n  throw err;\n}","preventionTips":["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"],"tags":["discord","http","json","network"],"backgroundTag":"invalid-json-response","analyzedSha":"01ad8584922b5d85292b1723cae71fa0d9b07a19","analyzedAt":"2026-09-10T03:14:50.855Z","contentChangedAt":"2026-09-10T03:14:50.855Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}