openclaw - 💡(How to fix) Fix Discord `message read` and `search` return gzip-compressed binary instead of parsed JSON

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…

Discord REST API responses for message action=read, action=search, and action=channel-info return raw gzip-compressed binary data instead of decompressed JSON. This causes:

  • read: TypeError: (intermediate value).map is not a function — the .map() call on the REST response fails because coerceResponseBody returns a binary string instead of an array
  • search/channel-info: garbled \u001f\u008b\u0008\u0000... (gzip magic bytes) in the result instead of parsed JSON
  • list-pins with empty results works fine (likely too small to trigger compression)

Error Message

if (!Array.isArray(messages)) throw new Error("Unexpected Discord response: expected message array");

Root Cause

  • read: TypeError: (intermediate value).map is not a function — the .map() call on the REST response fails because coerceResponseBody returns a binary string instead of an array
  • search/channel-info: garbled \u001f\u008b\u0008\u0000... (gzip magic bytes) in the result instead of parsed JSON
  • list-pins with empty results works fine (likely too small to trigger compression)

Fix Action

Fix / Workaround

  1. channel-actions.runtime dispatches handleDiscordAction({ action: "readMessages", ... })
  2. runtime calls discordMessagingActionRuntime.readMessagesDiscord(channelId, query, ctx.withOpts())
  3. readMessagesDiscordlistChannelMessages(rest, channelId, params)rest.get(...)
  4. RequestClient.executeRequest does:
    const response = await (this.customFetch ?? fetch)(url, { method, headers, body, signal });
    const parsed = coerceResponseBody(await response.text());
  5. response.text() returns raw gzip bytes as a string (not decompressed)
  6. coerceResponseBody tries JSON.parse(), fails, returns the raw binary string
  7. Back in runtime, line 443: (await readMessagesDiscord(...)).map(msg => ctx.normalizeMessage(msg)).map() on a string throws TypeError

Code Example

const response = await (this.customFetch ?? fetch)(url, { method, headers, body, signal });
   const parsed = coerceResponseBody(await response.text());

---

const messages = await readMessagesDiscord(channelId, query, opts);
if (!Array.isArray(messages)) throw new Error("Unexpected Discord response: expected message array");
RAW_BUFFERClick to expand / collapse

Summary

Discord REST API responses for message action=read, action=search, and action=channel-info return raw gzip-compressed binary data instead of decompressed JSON. This causes:

  • read: TypeError: (intermediate value).map is not a function — the .map() call on the REST response fails because coerceResponseBody returns a binary string instead of an array
  • search/channel-info: garbled \u001f\u008b\u0008\u0000... (gzip magic bytes) in the result instead of parsed JSON
  • list-pins with empty results works fine (likely too small to trigger compression)

Reproduction

  1. Configure a Discord channel with actions.messages: true and actions.search: true
  2. Call message action=read target=channel:<id> limit=20
  3. Observe: TypeError: (intermediate value).map is not a function
  4. Call message action=search channelId=<id> guildId=<id> query=the
  5. Observe: garbled binary in results

Root cause trace

  1. channel-actions.runtime dispatches handleDiscordAction({ action: "readMessages", ... })
  2. runtime calls discordMessagingActionRuntime.readMessagesDiscord(channelId, query, ctx.withOpts())
  3. readMessagesDiscordlistChannelMessages(rest, channelId, params)rest.get(...)
  4. RequestClient.executeRequest does:
    const response = await (this.customFetch ?? fetch)(url, { method, headers, body, signal });
    const parsed = coerceResponseBody(await response.text());
  5. response.text() returns raw gzip bytes as a string (not decompressed)
  6. coerceResponseBody tries JSON.parse(), fails, returns the raw binary string
  7. Back in runtime, line 443: (await readMessagesDiscord(...)).map(msg => ctx.normalizeMessage(msg)).map() on a string throws TypeError

Why response.text() returns gzip

Node 26's built-in fetch handles gzip decompression correctly (verified independently with httpbin.org/gzip). The issue appears specific to the Discord REST client's response handling or a mismatch in how the Discord API advertises/delivers compressed responses.

No Discord proxy is configured. No custom fetch override is active.

Suggested fix

Add defensive decompression in coerceResponseBody or the executeRequest response path — if response.text() returns content starting with gzip magic bytes (0x1f 0x8b), decompress before parsing. Alternatively, ensure the Discord RequestClient sets appropriate Accept-Encoding headers and/or handles Content-Encoding: gzip responses.

Also add defensive array-check in the readMessages handler:

const messages = await readMessagesDiscord(channelId, query, opts);
if (!Array.isArray(messages)) throw new Error("Unexpected Discord response: expected message array");

Environment

  • OpenClaw 2026.5.10-beta.3 (6d7dcd9)
  • Node v26.0.0
  • macOS (Apple Silicon)
  • No Discord proxy configured
  • NODE_EXTRA_CA_CERTS set (standard OpenClaw cert)

Affected files

  • extensions/discord/src/rest-client.tsRequestClient.executeRequest / coerceResponseBody
  • extensions/discord/src/actions/runtime.messaging.messages.tsreadMessages handler (line 443 in dist)
  • extensions/discord/src/actions/runtime.messaging.search.tssearchMessages handler

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING