#Bug Report: Tool-call responses duplicated in webchat; pre-tool text routes to Discord DM

1 messages · Page 1 of 1 (latest)

vague iron
#

Bug Report: Tool-call responses duplicated in webchat; pre-tool text routes to Discord DM

Version: 2026.3.2
Setup: Discord bot (2 accounts: royal, eagleeye), webchat (Control UI)

Symptoms:

Responses containing tool calls are delivered N+1 times in webchat (1 tool call = 2-3x, 2 tool calls = 3x+)
Text written before a tool call routes to Discord DM instead of webchat — even with dmPolicy: disabled
Responses with NO tool calls deliver correctly (1x)
Persists across: full Mac restart, fresh browser window, cleared browser storage, /new
Trigger: Started after a config patch that briefly set dmPolicy: allowlist on Discord royal account, then reverted to disabled

Inbound metadata shows chat_id: channel:1473772723720159312 (a Discord DM channel ID) on webchat sessions — this appears to be the root cause of split routing

Config: dmPolicy: disabled, one gateway process via LaunchAgent, no duplicate sessions in session store

lost sirenBOT
#

To help others find answers, you can mark your question as solved via Right click solution message -> Apps -> âś… Mark Solution

lapis cargoBOT
#

This symptom set lines up really cleanly with stale session routing metadata leaking into chat.send (WebChat/Control UI), not with dmPolicy.

What’s probably happening (based on gateway code)

When you use Control UI/WebChat it calls the gateway RPC chat.send. That handler will sometimes inherit a “deliverable route” from the session store (deliveryContext / lastChannel / lastTo). If that inherited route says “Discord DM channel:1473…”, the gateway sets:

  • OriginatingChannel = "discord"
  • OriginatingTo = "channel:1473..."

Then the generic reply dispatcher does this:

  • Block text (the “pre-tool-call” text) gets routed to the originating channel (Discord DM) and is not mirrored back to WebChat (mirror=false for blocks/tools)
    → exactly matches “text written before a tool call routes to Discord DM”
  • Final replies can get mirrored into the session transcript, so they still show up in WebChat.

Tool calls tend to create extra “block” boundaries, which is why the behavior correlates so strongly with tool use.

Why you see duplicates in WebChat

#

If your WebChat session is effectively “Discord-routed”, you can end up with the same assistant output arriving via:

  • the normal WebChat run events, and/or
  • transcript mirroring from the Discord-routed send

…which shows up as N+1-ish repeats depending on how many assistant/tool boundaries happen in that run.

Fastest workaround (no code changes)

  1. Don’t just /new — /new resets the conversation inside the same session key, so it won’t necessarily clear the bad stored route.
  2. In Dashboard / Control UI → Sessions, find the session you’re chatting in from WebChat and delete it (or create a brand-new session key that is clearly WebChat/main-scoped).
  3. Re-open WebChat and start a fresh session.

If you paste the sessionKey you see in WebChat (and optionally the redacted session-store entry fields: channel, lastChannel, lastTo, deliveryContext), we can confirm in 10 seconds whether it’s inheriting a Discord DM route.

Strong suggestion: upgrade to 2026.3.3

Your version is 2026.3.2, and 2026.3.3 includes routing fixes that sound directly related (changelog: “Routing/session duplicate suppression… avoid cross-surface duplicate replies…”).

If you file/extend the GitHub issue

#

Include:

  • WebChat sessionKey
  • the session store entry for that key (redact tokens)
  • one gateway log snippet showing the inherited route (discord channel id) during chat.send

That should make this very actionable for maintainers.

vague iron
#

This is my agents response:

Krill nailed it. Exactly what I suspected but couldn't confirm — stale deliveryContext on the agent:main:main session inherited the Discord DM route when dmPolicy was briefly allowlist. /new doesn't fix it because it reuses the same session key.

Two-step fix:

Step 1 — Upgrade to 2026.3.3 (has the routing fix). From terminal, LaunchAgent unload first to avoid crash-loop:

launchctl unload ~/Library/LaunchAgents/ai.openclaw.gateway.plist
sudo npm install -g openclaw@latest
launchctl load ~/Library/LaunchAgents/ai.openclaw.gateway.plist
Step 2 — Delete the stale session. I can do it now if you want, or after the upgrade. The key is agent:main:main in ~/.openclaw/agents/main/sessions/sessions.json. Deleting that entry forces webchat to create a clean session with no inherited Discord route.

Upgrade first — 3.3 may handle the session cleanup automatically. Want to run it?

lapis cargoBOT
#

Yep — that plan is the right shape. Two small tweaks so it’s safer/less “launchd voodoo”:

1) Upgrade to 2026.3.3

You usually don’t need to unload/load the LaunchAgent. The docs recommend:

  • Update (global install):
    • npm i -g openclaw@latest (avoid sudo if you’re on nvm/asdf/etc)
    • or re-run the installer: curl -fsSL https://openclaw.ai/install.sh | bash -s -- --no-onboard

Then run the boring-but-important sequence:

openclaw doctor
openclaw gateway restart

Docs: https://docs.openclaw.ai/install/updating (and FAQ restart section: https://docs.openclaw.ai/help/faq)

#

2) Delete the stale session route (the real fix)

Also yes: /new won’t fix this, because it keeps the same session key + its stored deliveryContext.

Safest path is via Dashboard → Sessions → delete the affected session (so you’re not hand-editing JSON).

If you do manually delete the agent:main:main entry in ~/.openclaw/agents/main/sessions/sessions.json, just:

  • make a backup copy first
  • restart the gateway after

After those two steps, the “pre-tool text goes to Discord DM” part should disappear immediately, and the WebChat N+1 duplication usually goes away with it (and/or with the 2026.3.3 routing fixes).

If it still reproduces on 2026.3.3: paste the redacted agent:main:main session entry (the fields around deliveryContext / lastChannel / lastTo) and we’ll know exactly why it’s still inheriting the DM route.

vague iron
#

GatewayRequestError: Cannot delete the main session (agent:main:main).

lapis cargoBOT
#

That error is expected: agent:main:main is the protected “main session” key, and the gateway explicitly blocks sessions.delete for it (Cannot delete the main session…).

What to do instead:

Do this first: upgrade to 2026.3.3

Given you’re on 2026.3.2, I’d upgrade + restart before touching the session store. 2026.3.3 has routing/duplicate-suppression fixes that are very likely the real cure here.

Recommended sequence:

npm i -g openclaw@latest   # (no sudo if you’re on nvm/asdf/etc)
openclaw doctor
openclaw gateway restart

If it still happens on 2026.3.3: clear the stale route fields (don’t delete)

Since you can’t delete agent:main:main, the “hard reset” is to remove the routing metadata from its entry in:

#

~/.openclaw/agents/main/sessions/sessions.json

Specifically, in the agent:main:main object, remove (or set to null / delete the keys):

  • deliveryContext
  • lastChannel
  • lastTo
  • lastAccountId
  • lastThreadId

Do it with the gateway stopped so it doesn’t rewrite the file while you edit:

openclaw gateway stop
# edit the JSON (make a backup copy first)
openclaw gateway start
#

Note: sessions.reset / /new won’t necessarily fix this because (at least in current code) resets preserve lastChannel/lastTo.

If you confirm after upgrading whether the issue persists, I can tell you whether you even need the manual edit step.

vague iron
#

Version 3.3 isn't available yet.

lapis cargoBOT
#

Yep — npm agrees with you right now.

  • npm “latest” is still 2026.3.2 (so npm i -g openclaw@latest won’t get you 2026.3.3 yet).
  • The repo already has version: 2026.3.3, but it hasn’t hit the npm dist-tag.

So: treat “upgrade to 3.3” as either “wait for publish” or “switch to a git/dev install”. In the meantime you can still fix this on 2026.3.2.

Immediate fix on 2026.3.2 (since you can’t delete agent:main:main)

You don’t need to delete the main session — you need to clear its stale route fields.

  1. Stop the gateway (so it won’t rewrite while you edit):
openclaw gateway stop
  1. Backup + edit:
#

File: ~/.openclaw/agents/main/sessions/sessions.json
Key: "agent:main:main"

Inside that object, remove these fields if present:

  • deliveryContext
  • lastChannel
  • lastTo
  • lastAccountId
  • lastThreadId
  1. Start gateway again:
openclaw gateway start
#

Then refresh Control UI and retry a tool-call prompt.

Prevent it from coming back (recommended workaround until 3.3 lands)

Right now your Discord DMs are sharing agent:main:main because session.dmScope=main (that’s the default for Discord: docs confirm DMs collapse into the main session).

If you set:

{
  session: { dmScope: "per-account-channel-peer" }
}

…then Discord DMs (especially with 2 accounts) won’t keep poisoning the main session’s last-route metadata.

Docs: https://docs.openclaw.ai/concepts/session (dmScope) and Discord channel doc mentions the default behavior.