openclaw - 💡(How to fix) Fix [Bug]: Discord message search fails with "guildId required" — no session/channel fallback [1 pull requests]

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…

The Discord message tool's search action throws ToolInputError: guildId required whenever the model does not pass an explicit guildId. In the captured session the agent was running inside a known guild channel, but the guild id was not surfaced to the model (session metadata showed channel/provider/surface/chat_type but not guildId/channelId) and the handler has no fallback to the current session's guild — so the model had no value to pass and the action was unusable from a normal in-channel flow.

Error Message

Gateway journal — two independent occurrences on separate days (conn/id redacted):

May 29 22:52:44 host node[115782]: [ws] res ✗ message.action 26ms errorCode=UNAVAILABLE
errorMessage=ToolInputError: guildId required channel=discord error=ToolInputError: guildId required May 30 22:42:04 host node[141396]: [ws] res ✗ message.action 27ms errorCode=UNAVAILABLE
errorMessage=ToolInputError: guildId required channel=discord error=ToolInputError: guildId required

Session JSONL — assistant tool call (call_id redacted; query text redacted to <example prior-topic query>):

{"role":"assistant","content":[{"type":"toolCall","name":"message", "arguments":{"action":"search","query":"<example prior-topic query>","limit":20,"accountId":"default"}}]}

Session JSONL — tool result (isError:true), content verbatim:

ToolInputError: guildId required

Root Cause

Root cause (source on main @ 66bbcfd, version 2026.5.31):

Fix Action

Fixed

Code Example

const guildId = readStringParam(ctx.params, "guildId", { required: true });

---

if (required) { throw new ToolInputError(`${label} required`); }

---

# Gateway journal — two independent occurrences on separate days (conn/id redacted):
May 29 22:52:44 host node[115782]: [ws] res ✗ message.action 26ms errorCode=UNAVAILABLE \
  errorMessage=ToolInputError: guildId required channel=discord error=ToolInputError: guildId required
May 30 22:42:04 host node[141396]: [ws] res ✗ message.action 27ms errorCode=UNAVAILABLE \
  errorMessage=ToolInputError: guildId required channel=discord error=ToolInputError: guildId required

# Session JSONL — assistant tool call (call_id redacted; query text redacted to <example prior-topic query>):
{"role":"assistant","content":[{"type":"toolCall","name":"message",
  "arguments":{"action":"search","query":"<example prior-topic query>","limit":20,"accountId":"default"}}]}

# Session JSONL — tool result (isError:true), content verbatim:
ToolInputError: guildId required
RAW_BUFFERClick to expand / collapse

Bug type

Behavior bug (incorrect output/state without crash)

Beta release blocker

No

Summary

The Discord message tool's search action throws ToolInputError: guildId required whenever the model does not pass an explicit guildId. In the captured session the agent was running inside a known guild channel, but the guild id was not surfaced to the model (session metadata showed channel/provider/surface/chat_type but not guildId/channelId) and the handler has no fallback to the current session's guild — so the model had no value to pass and the action was unusable from a normal in-channel flow.

Steps to reproduce

  1. Run OpenClaw with the Discord plugin, with the bot active in a guild (server) channel.
  2. From that channel, ask the agent something that leads it to search Discord history (e.g. a prior shopping/topic query).
  3. The model invokes the Discord message tool with action: "search" and a query, but no guildId (it has none available — the guild id isn't in its context; see Additional information).
  4. The tool call fails immediately with ToolInputError: guildId required.

Expected behavior

Search should be usable from within a guild channel without the model having to know the guild id — either by defaulting guildId to the current session's guild when safe (mirroring how other message actions resolve the current channel via ctx.resolveChannelId() / readCurrentDiscordTarget), or by exposing the current guild id to the model / tool-invocation context so it can be passed. If no guild can be resolved, the error should clearly state that guildId is required for guild-scoped search and how to supply it, instead of the bare guildId required. (Leaving the architecture choice to maintainers — the guild-scoping itself is correct and should stay.)

Actual behavior

The call fails with ToolInputError: guildId required and the task stalls. The model has no recovery path: the guild id is not part of the model-visible session metadata, and unlike fetchMessage (which soft-reads guildId and can derive it from a message link) the searchMessages handler requires it outright with no fallback to the (known) session guild.

Root cause (source on main @ 66bbcfd, version 2026.5.31):

  • extensions/discord/src/actions/runtime.messaging.messages.ts, case "searchMessages" (lines 186-188):
    const guildId = readStringParam(ctx.params, "guildId", { required: true });
    No fallback to the session / current guild.
  • The error string is thrown by core src/agents/tools/common.ts, readStringParam (~line 113):
    if (required) { throw new ToolInputError(`${label} required`); }
    label defaults to the key, so the message is exactly guildId required.
  • Contrast the sibling fetchMessage handler in the same file (~line 69), which soft-reads guildId (readStringParam(ctx.params, "guildId")), can derive it from a messageLink, and emits a descriptive combined error instead.
  • Discord's message-search REST endpoint is guild-scoped (GET /guilds/{guildId}/messages/search; see send.messages.tssearchGuildMessages), so guildId is genuinely required at the API boundary. The defect is missing context plumbing and a poor error, not the validation itself.

Secondary (lower priority than the guildId issue): the handler also requires content (lines 189-191) while the model naturally sends query, so even with a guild supplied a query-shaped call would fail validation. Worth aligning the param name or accepting both — but the primary bug is the missing guild context.

OpenClaw version

@openclaw/discord 2026.5.27 on gateway/core 2026.5.28 (installed). Confirmed present on main @ 66bbcfd (2026.5.31) via local source inspection of a fresh clone: the required: true on guildId (and the metadata/tool-context gap) are unchanged.

Operating system

Ubuntu 24.04.4 LTS

Install method

npm global (@openclaw/discord under ~/.openclaw/npm), gateway via systemd. Node v22.22.2.

Model

GPT-5-class agent via the Codex harness (OpenClaw model_provider: openai).

Provider / routing chain

openclaw -> codex (acp) harness -> openai

Logs, screenshots, and evidence

Real captured output from a live OpenClaw + Discord session (reporter's install). Triggered from a guild channel (session key agent:main:discord:channel:<channelId-redacted>; guild id redacted — it is known to the runtime but never reaches the model). Model gpt-5.5 via openai-codex.

# Gateway journal — two independent occurrences on separate days (conn/id redacted):
May 29 22:52:44 host node[115782]: [ws] res ✗ message.action 26ms errorCode=UNAVAILABLE \
  errorMessage=ToolInputError: guildId required channel=discord error=ToolInputError: guildId required
May 30 22:42:04 host node[141396]: [ws] res ✗ message.action 27ms errorCode=UNAVAILABLE \
  errorMessage=ToolInputError: guildId required channel=discord error=ToolInputError: guildId required

# Session JSONL — assistant tool call (call_id redacted; query text redacted to <example prior-topic query>):
{"role":"assistant","content":[{"type":"toolCall","name":"message",
  "arguments":{"action":"search","query":"<example prior-topic query>","limit":20,"accountId":"default"}}]}

# Session JSONL — tool result (isError:true), content verbatim:
ToolInputError: guildId required

Impact and severity

  • Affected: any agent run on Discord that uses the search message action from a guild channel without manually supplying guildId.
  • Severity: Medium for Discord message-search workflows. Core Discord chat/reply behavior continues to work, but history search from guild channels fails whenever the model omits guildId, which appears to be the natural/default tool call shape.
  • Frequency: Always when guildId is omitted (reproduced on two separate days in this install).
  • Consequence: the agent cannot search Discord history; the task fails with an opaque error and no recovery path, since guildId is not exposed to the model.

Additional information

Why the model omits guildId: the trusted tool-invocation context (toolContext) carries currentChannelProvider / currentChannelId but has no currentGuildId, and the Discord session metadata projected to the model (built in extensions/discord/src/channel.ts / channel.conversation.ts, surfaced via core src/auto-reply/reply/inbound-meta.ts) does not include guildId. The guild id IS known to the runtime at this point — the session key is agent:main:discord:channel:<channelId> and the inbound Discord source carries guildId — it simply never gets threaded into the model context or the tool-invocation context, so the handler has nothing to default from.

Suggested fix direction (context plumbing + clearer error; the validation itself is correct):

  1. Add an optional currentGuildId to the tool-invocation context and populate it from the inbound Discord session source (source.guildId is already available at inbound).
  2. In the searchMessages handler, default guildId to that session guild when the param is absent (mirroring readCurrentDiscordTarget / ctx.resolveChannelId), keeping the existing assertGuildReadTargetAllowed / assertReadTargetAllowed authorization checks unchanged.
  3. When no guild can be resolved, throw a descriptive error explaining guildId is required for guild-scoped search and how to supply it.
  4. Optionally surface guildId in the model-visible session metadata for guild channels.
  5. Accept query as an alias for content (or rename) to fix the secondary param mismatch.

This affects only the Discord plugin context path; the REST layer is correct. Happy to open a PR with the fix + tests (extending extensions/discord/src/actions/runtime.test.ts and channel-actions.test.ts) if the approach looks right.


Filed with AI assistance (Claude Code). Evidence above is real captured output from the reporter's live OpenClaw + Discord install.

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…

FAQ

Expected behavior

Search should be usable from within a guild channel without the model having to know the guild id — either by defaulting guildId to the current session's guild when safe (mirroring how other message actions resolve the current channel via ctx.resolveChannelId() / readCurrentDiscordTarget), or by exposing the current guild id to the model / tool-invocation context so it can be passed. If no guild can be resolved, the error should clearly state that guildId is required for guild-scoped search and how to supply it, instead of the bare guildId required. (Leaving the architecture choice to maintainers — the guild-scoping itself is correct and should stay.)

Still need to ship something?

×6

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

Back to top recommendations

TRENDING

openclaw - 💡(How to fix) Fix [Bug]: Discord message search fails with "guildId required" — no session/channel fallback [1 pull requests]