#Triple Message Delivery in Discord

1 messages · Page 1 of 1 (latest)

pure forge
#

triple message delivery in Discord channel sessions, each user message and system message appears 3x in agent context. Causing 3-6 mintes between simple chat answers.

grand craterBOT
#

Triple-delivery almost always means the Gateway is ingesting the same Discord event 3 times (so it records 3 turns, which then makes each “simple answer” take forever).

The two common causes:

1) You have multiple Discord accounts enabled (channels.discord.accounts.*)

If you’ve got 3 enabled accounts that can all “see” the same guild/channel, OpenClaw will happily route the same MESSAGE_CREATE through each account (and there’s no dedupe across accountIds).

How to confirm

  • Run:
    openclaw channels status --probe
    
    and check how many Discord accounts it reports as enabled.

Fix

  • In config, disable the extra accounts (or remove them), leaving exactly one enabled for that guild/channel, e.g.
#
  {
    channels: {
      discord: {
        accounts: {
          default: { enabled: true },
          work: { enabled: false },
          test: { enabled: false },
        },
      },
    },
  }
  • Then:
    openclaw gateway restart
    
#

2) You’re accidentally running multiple Gateways pointing at the same state/config

This happens a lot when you have a background service and also run openclaw gateway manually (or you run 2 services without isolated profiles). That can create duplicated session ingestion / weird replay behavior.

How to confirm

openclaw gateway status
openclaw status --all

Fix


If the bot is also “slow” / you see timeout logs

Check openclaw logs --follow while sending a single message. If you see lines like:

#
  • ... timed out after ... for event MESSAGE_CREATE
    then bump the listener timeout (this can also manifest as duplicates / reprocessing symptoms):

  • single-account: channels.discord.eventQueue.listenerTimeout

  • multi-account: channels.discord.accounts.<accountId>.eventQueue.listenerTimeout

Docs: https://docs.openclaw.ai/channels/discord (section “Long-running handlers time out or duplicate replies”)


If you paste (1) openclaw --version and (2) the redacted output of openclaw channels status --probe, I can tell you which branch you’re in (multi-account vs multi-gateway) in one shot.

pure forge
#

willdoylejarvis@Wills-Mac-mini ~ % openclaw --version
2026.3.1

Gateway not reachable: Error: gateway timeout after 10000ms
Gateway target: ws://127.0.0.1:18789
Source: local loopback
Config: /Users/willdoylejarvis/.openclaw/openclaw.json
Bind: loopback
Gateway not reachable; showing config-only status.
Config: /Users/willdoylejarvis/.openclaw/openclaw.json
Mode: local

  • Discord ada: enabled, configured, token:config
  • Discord alex: enabled, configured, token:config
  • Discord atlas: enabled, configured, token:config
  • Discord blake: enabled, configured, token:config
  • Discord bridge: enabled, configured, token:config
  • Discord casey: enabled, configured, token:config
  • Discord coach: enabled, configured, token:config
  • Discord default: enabled, configured, token:config
  • Discord ember: enabled, configured, token:config
  • Discord finn: enabled, configured, token:config
  • Discord madison: enabled, configured, token:config
  • Discord marcus: enabled, configured, token:config
  • Discord morgan: enabled, configured, token:config
  • Discord ops: enabled, configured, token:config
  • Discord parker: enabled, configured, token:config
  • Discord riley: enabled, configured, token:config
  • Discord sage: enabled, configured, token:config
  • Discord sterling: enabled, configured, token:config
  • iMessage default: disabled, configured
grand craterBOT
#

That output basically explains the “triple message” instantly:

You have a bunch of Discord accounts enabled (ada, alex, atlas, … default, etc). Each enabled Discord account runs its own Discord gateway connection + message handler. So if 3 of those bots/accounts are in the same guild/channel and allowed to read it, OpenClaw will ingest the same user message 3 times → you see every message/system-event tripled in the agent context, and everything gets painfully slow.

Fix: ensure only ONE Discord account can see that channel

Pick the one bot/account you actually want for this server/channel (often default), then do one of these:

Option A (simplest): disable all the extra accounts

Edit ~/.openclaw/openclaw.json and set enabled: false for every unused account under:
channels.discord.accounts.<id>.enabled

Or via CLI (example disables one):

openclaw config set channels.discord.accounts.ada.enabled false --json

Do that for all the ones you don’t want active.

#

Then restart:

openclaw gateway restart

Option B: keep multiple accounts, but isolate guild/channel allowlists

If you want multiple Discord bots for different purposes, make sure only one of them allowlists this guild/channel (channels.discord.accounts.<id>.guilds...) so their allowed scopes don’t overlap.


Separate issue in your paste: Gateway is down

You also have:

Gateway not reachable: ... ws://127.0.0.1:18789

So after you fix the config, make sure it’s actually running:

#
openclaw gateway status
openclaw gateway start   # or: openclaw gateway

If it won’t stay up, run:

openclaw logs --follow

and paste the first obvious error block.

If you tell me which one Discord account you want to keep for this thread (e.g. default), I can paste a copy/paste shell loop that disables the rest cleanly.

pure forge
#

File logs: /tmp/openclaw/openclaw-2026-03-04.log
Command: /opt/homebrew/Cellar/node/25.5.0/bin/node /opt/homebrew/lib/node_modules/openclaw/dist/index.js gateway --port 18789
Service file: ~/Library/LaunchAgents/ai.openclaw.gateway.plist
Service env: OPENCLAW_GATEWAY_PORT=18789

Config (cli): ~/.openclaw/openclaw.json
Config (service): ~/.openclaw/openclaw.json

Gateway: bind=loopback (127.0.0.1), port=18789 (service args)
Probe target: ws://127.0.0.1:18789
Dashboard: http://127.0.0.1:18789/
Probe note: Loopback-only gateway; only local clients can connect.

Runtime: running (pid 49142, state active)
RPC probe: ok

Listening: 127.0.0.1:18789
Other gateway-like services detected (best effort):

  • ai.openclaw.config.guard (user, plist: /Users/willdoylejarvis/Library/LaunchAgents/ai.openclaw.config.guard.plist)
  • ai.vidclaw.dashboard (user, plist: /Users/willdoylejarvis/Library/LaunchAgents/ai.vidclaw.dashboard.plist)
  • com.openclaw.codex-auth-sync (user, plist: /Users/willdoylejarvis/Library/LaunchAgents/com.openclaw.codex-auth-sync.plist)
  • com.openclaw.ypdr-keepalive (user, plist: /Users/willdoylejarvis/Library/LaunchAgents/com.openclaw.ypdr-keepalive.plist)
  • com.otathletics.ota-enrollment-sync (user, plist: /Users/willdoylejarvis/Library/LaunchAgents/com.otathletics.ota-enrollment-sync.plist)
  • com.otathletics.ota-journey (user, plist: /Users/willdoylejarvis/Library/LaunchAgents/com.otathletics.ota-journey.plist)
  • com.otathletics.tally-coach-availability-sync (user, plist: /Users/willdoylejarvis/Library/LaunchAgents/com.otathletics.tally-coach-availability-sync.plist)
  • com.otathletics.tally-intake-sync (user, plist: /Users/willdoylejarvis/Library/LaunchAgents/com.otathletics.tally-intake-sync.plist)
#
  • com.otathletics.tally-preference-sync (user, plist: /Users/willdoylejarvis/Library/LaunchAgents/com.otathletics.tally-preference-sync.plist)
  • com.otathletics.tally-survey-sync (user, plist: /Users/willdoylejarvis/Library/LaunchAgents/com.otathletics.tally-survey-sync.plist)
    Cleanup hint: launchctl bootout gui/$UID/ai.openclaw.gateway
    Cleanup hint: rm ~/Library/LaunchAgents/ai.openclaw.gateway.plist

Recommendation: run a single gateway per machine for most setups. One gateway supports multiple agents (see docs: /gateway#multiple-gateways-same-host).
If you need multiple gateways (e.g., a rescue bot on the same host), isolate ports + config/state (see docs: /gateway#multiple-gateways-same-host).

grand craterBOT
#

Nice — that openclaw gateway status output shows one Gateway (RPC probe ok), so this is not a “multiple gateways fighting each other” situation.

So we’re back to the real culprit from your earlier status dump:

You have many Discord accounts enabled (ada/alex/atlas/…/default/…). If 3 of those bots are in the same guild/channel and allowed, you’ll get exactly what you described: every inbound message (and the derived “system” events) lands in the session transcript 3 times.

Fast way to prove it (takes 20s)

  1. In one terminal:
openclaw logs --follow
  1. Send one message in the problematic Discord channel.

  2. In the logs, you should see that single Discord messageId=... being processed multiple times — typically you’ll see it tagged/preceded by different accountIds (3 different bots).

Quick “make it stop” fix (disable everything except default)

#

Copy/paste this (based on the account ids you posted):

for id in ada alex atlas blake bridge casey coach ember finn madison marcus morgan ops parker riley sage sterling; do
  openclaw config set "channels.discord.accounts.${id}.enabled" false --json
done

openclaw gateway restart

(You can re-enable any one later with ...enabled true --json.)

If you actually want multiple Discord bots

Then don’t disable them globally — instead ensure only one of them allowlists this guild/channel (per-account channels.discord.accounts.<id>.guilds...) so their routing scopes don’t overlap.

If you paste ~10 lines of your channels.discord.accounts config with tokens removed, I can point to the exact allowlist knobs to isolate them cleanly.

#

That chunk at the bottom of openclaw gateway status is generic hygiene output — it’s basically saying “I see other launch agents on your machine; if you ever want to fully uninstall the gateway service, here’s how.”

It does not indicate you have 3 gateways running.

In your earlier status output the smoking gun was:

Discord ada: enabled ...
Discord alex: enabled ...
… (lots more) …

That’s what causes triple (or N‑tuple) ingestion: multiple enabled Discord accounts/bots in the same guild/channel.

What I’d do next

  1. Disable everything except the one bot you want for this server/channel (the loop I sent), then:
    openclaw gateway restart
    
#
  1. Verify it took:

    openclaw channels status --probe
    

    You should see only one “Discord <id>: enabled”.

  2. Send a single test message in the channel and confirm it only appears once in the session context.

If you do need multiple Discord bots enabled long-term, tell me which 3 are in the problematic server and I’ll show the clean per-account allowlist layout so only one of them can see that guild/channel.

pure forge
#

From bot in channel: Still seeing doubles. Went from 3x to 2x — progress but not fully fixed. The top-level discord token and the default account token are likely both running gateway connections for #executive.

Let me check — the top-level channels.discord has a token AND accounts.default has a token. Both allowlist #executive. That's the remaining duplicate.

Want me to remove #executive from the top-level guild config entirely? The default account already handles it.

grand craterBOT
#

Your theory (“top-level channels.discord.token + accounts.default.token = two Discord gateway connections”) sounds plausible, but with the current code it shouldn’t actually spin up a second “implicit default” account as long as channels.discord.accounts exists.

What does cause the exact “3x → 2x” symptom is:

  • you successfully disabled one of the bots/accounts
  • but there’s still one more enabled Discord account that can see #executive (often because it’s inheriting the top-level channels.discord.guilds allowlist)

So: removing #executive from the top-level config is a good move — not because it creates a 2nd connection by itself, but because top-level channels.discord.guilds applies to every enabled account unless you override per-account.

Recommended cleanup for multi-account Discord (prevents this forever)

1) Make the top-level Discord config “neutral”

  • remove (or empty) channels.discord.guilds at the top level
  • (optional but strongly recommended) remove channels.discord.token if you’re using channels.discord.accounts.*.token — it avoids confusion

2) Put all allowlisting under the one account that should handle it

e.g. only:

#
  • channels.discord.accounts.default.guilds.<yourGuild>.channels.executive.allow = true

3) Verify what’s still enabled

Run:

openclaw channels status --probe

If it shows more than one Discord <id>: enabled, that’s your remaining “double”.

4) Important: old duplicates linger in the session

Even after you fix routing, the existing Discord thread/session transcript may still contain duplicated earlier messages (until they fall out of historyLimit). To sanity-check the fix, test in a fresh thread or after starting a fresh session context.

If you paste the current openclaw channels status --probe output, I can tell you immediately which 2 accounts are still enabled and likely overlapping.

pure forge
#

Summary of what we've verified:
âś… No top-level guilds or token
âś… Only accounts.default sees #executive
âś… All 18 bot tokens are unique
âś… Only 1 gateway process running
✅ ~18 Discord WebSocket connections (correct — one per bot)

The tripling is happening inside the framework's prompt construction, not at the Discord or config level. Krill's advice was solid but we'd already fixed everything they suggested.

grand craterBOT
#

If you’ve genuinely got only accounts.default allowed for that channel, then you’re right: this stops being a Discord/config “multiple listeners” problem and starts being either:

  1. Old duplicated transcript history still sitting in the session, or
  2. A real context-building bug (history/prefix assembly causing repeated blocks), even with single ingestion.

Two high-signal checks/workarounds:

1) Hard reset the session (to rule out “old dupes still in history”)

Even after you fix routing, the existing Discord channel session can remain polluted (and every new prompt will keep re-sending that polluted history).

In the channel/thread, send as a standalone message:

  • /new (or /reset)

Then send a single “hello” and see if the doubling/tripling is still present.

Docs: https://docs.openclaw.ai/tools/slash-commands (see /new + /reset)

#

2) Temporarily disable the “since last reply” history feature

There’s a known “looks like duplicated context” footgun when history is injected as both:

  • a “chat history since last reply” context block, and/or
  • extra text in the body

Quick isolation test:

openclaw config set channels.discord.historyLimit 0 --json
openclaw gateway restart

If that makes the duplication disappear immediately, we’ve narrowed it to the history/prompt-prefix path (not Discord delivery).

Config reference (historyLimit): https://docs.openclaw.ai/gateway/configuration-reference (search “messages.groupChat.historyLimit” / “channels.<channel>.historyLimit”)


#

If it still duplicates after /new and channels.discord.historyLimit=0

That’s squarely “bug” territory. The most useful thing to file is a GitHub issue with proof of whether the inbound message is being recorded multiple times or only duplicated at prompt render:

  1. Set file logs to debug:
openclaw config set logging.level \"debug\" --json
openclaw gateway restart
  1. Send one message, then grep the log for that Discord message.id (the snowflake). If you paste ~30 lines around the relevant entries (redacted), we can tell:
  • multiple preflight/process runs (ingestion duplicate), vs
  • single run but duplicated prompt blocks (prompt builder duplicate).

If it’s the latter, please file: https://github.com/openclaw/openclaw/issues
Include: version (2026.3.1), channels.discord.historyLimit, whether /new fixes it, and one redacted log excerpt around a single message id.

If you paste your current channels.discord.historyLimit + messages.groupChat.historyLimit values and confirm whether /new changes anything, I can tell you which branch you’re in.

pure forge
#

Hey Krill — followed your advice, here's what we found:

Config is verified clean:
No top-level channels.discord.guilds or channels.discord.token — removed those in the prior session
Only accounts.default has #executive (1469389732055351451) in its channel allowlist
All 18 bot accounts have unique tokens (verified programmatically)
Single gateway process running
~18 Discord WebSocket connections (one per bot, correct)

Still tripled: Messages are arriving 3x in the agent's prompt even after /new and a full update to 2026.3.2.

Probe issue: openclaw channels status --probe says "Gateway not reachable: Error: gateway timeout after 10000ms" — but the gateway IS actively processing Discord messages (we're talking through it). The CLI can't connect to ws://127.0.0.1:18789 even though Discord message flow works fine.
Error log notable: Seeing "Slow listener detected: DiscordMessageListener took 75.8 seconds for event MESSAGE_CREATE" and heavy Anthropic API rate limit retries.

Any ideas on what else could cause the tripling? Feels like a framework-level prompt construction issue rather than config/routing.

grand craterBOT
#

Given what you’ve verified, there are two things left that can still explain “tripled inside the prompt” — and one of them also explains why the CLI probe times out while Discord keeps working.

1) You’re still effectively processing the same channel message in 3 separate runs (overlap), but it’s masked by session keying

Important nuance: Discord channel sessions do not include accountId in the session key:

agent:<agentId>:discord:channel:<channelId>

So if any other Discord account is still actually passing allowlist/mention gating for #executive, it will write into the same session transcript and it will look like “prompt duplication / tripling”.

The quickest way to prove/rule this out is to do an isolation run:

Temporarily disable 17 accounts, leave only accounts.default.enabled=true, restart gateway, then /new and test again.

Even if you believe allowlists are clean, this test is high-signal because it also drops you from 18 Discord WS connections → 1, which should reduce load and make the CLI probe stop timing out.

#

2) “Looks tripled” because the bot is slow + history injection (and you’re rate-limited hard)

With Slow listener ... 75.8s plus Anthropic 429 retries, you’re in the worst-case path where OpenClaw will attach additional context like:

  • Conversation history (normal session transcript)
  • Chat history since last reply (InboundHistory block)
  • sometimes extra “pending history” shaping in the inbound body

If you’re inspecting raw prompts, that can absolutely look like the same user message is repeated multiple times—especially when messages stack up while the bot is stuck retrying.

Fast isolation toggle:

openclaw config set channels.discord.historyLimit 0 --json
openclaw gateway restart

Then /new and test. If tripling disappears, the “duplicate” you’re seeing is coming from the history-injection path under slow runs (not Discord delivery).

#

Docs for historyLimit: https://docs.openclaw.ai/gateway/configuration-reference (search channels.<channel>.historyLimit)


Why channels status --probe times out while Discord still works

Discord message flow is inbound via Discord’s gateway, not via OpenClaw’s local WS RPC.

openclaw channels status --probe needs the Gateway to accept a new WS connection and respond quickly; under heavy load (18 WS connections + slow MESSAGE_CREATE handlers + rate-limit retry backoff), the Gateway can be “alive” but too busy to answer within the CLI’s 10s probe timeout.

So the CLI timeout is actually a useful symptom of: your gateway is overloaded.


One concrete next step (minimal friction)

Pick one of these to run next and paste the result:

  1. After disabling all but accounts.default, does it still triple? (yes/no)
#
  1. After channels.discord.historyLimit=0 + /new, does it still triple? (yes/no)

If either of those fixes it, we’ve got a clear root cause. If neither fixes it, it’s very likely a real bug — at that point the best path is a GitHub issue with a single messageId and a log excerpt showing whether the message handler ran 3 times or only once.

pure forge
#

neither path worked

#

Next fix (Option C): add a small inbound debounce for Discord.
It will drop rapid duplicates; tradeoff is if you send two messages within ~1s, they may coalesce.

Want me to apply messages.inbound.byChannel.discord = 1000 and test?
(Also: all other bots are still temporarily disabled from Option B; I’ll re‑enable after we finish this test.)

grand craterBOT
#

If (a) only accounts.default is enabled/allowed and (b) channels.discord.historyLimit=0 and (c) /new still shows “3x”, then we’re past the configuration surface. At this point I need to know which “3x” you mean, because there are two very different failure modes:

A) 3 separate runs/attempts (most likely with your 429 + slow-listener symptoms)

With heavy Anthropic 429 backoff, OpenClaw can end up doing “try → rate limit → retry → retry…”. If you’re looking at prompt debug output, that can look like “the prompt is tripled”, but it’s actually the same prompt rebuilt/sent 3 times.

How to confirm (super high-signal):
Pick ONE Discord message (copy its message ID) and then count how many times the gateway processed it.

LOG=/tmp/openclaw/openclaw-2026-03-04.log   # adjust date if needed
MSGID="14788...."

# How many Discord MESSAGE_CREATE handlers ran for that message?
grep -c "\"messageId\":\"$MSGID\"" "$LOG"

# How many inbound-session records were written for that message?
#
grep -c "\"MessageSid\":\"$MSGID\"" "$LOG" || true
  • If you see 3x handler entries for the same messageId, that’s true duplicate ingestion.
  • If you see 1x handler but multiple model/run attempt logs around it, that’s retries/backoff (not transcript duplication).

B) The session transcript really contains 3 copies (true duplication)

Then we should see multiple writes for the same MessageSid in the session store, and the quickest way to prove it is the log counts above.


Why I keep coming back to retries/backoff

You’re seeing:

  • Slow listener detected ... took 75.8 seconds for event MESSAGE_CREATE
  • “heavy Anthropic API rate limit retries”
  • CLI probe timing out while Discord still works
#

That combo screams “gateway is overloaded / retrying calls”, which can easily create the appearance of repeated prompt construction.


If you can paste one data point, we can finish this

Reply with just these two numbers for a single message id:

  1. grep -c "\"messageId\":\"<id>\"" ...
  2. grep -c "\"MessageSid\":\"<id>\"" ...

No secrets, no prompt dumps needed. Once we know whether it’s 3 ingests vs 1 ingest + 3 retries, the fix path is totally different (and if it’s true duplicate ingests with a single enabled account, that’s a solid GitHub issue).

#

Yes — inbound debounce is a good “Option C” to try as a mitigation, especially if what you’re getting is a rapid burst of duplicate Discord MESSAGE_CREATE events.

Tiny correction on the config key:

  • It’s messages.inbound.byChannel.discord, not messages.inbound.byChannel.discord = ... (and not messages.inbound.byChannel.discord at the root).

So the change you want is:

openclaw config set messages.inbound.byChannel.discord 1000 --json
openclaw gateway restart

(Keeping the other bots disabled for this test is perfect — makes the result unambiguous.)

Test plan

  1. /new in the channel/thread
#
  1. Send one message and wait
  2. Confirm whether the agent prompt still shows 3 copies of the inbound + system events

Docs reference (Inbound debounce): https://docs.openclaw.ai/gateway/configuration-reference (Messages → inbound → debounceMs/byChannel)

If 1000ms doesn’t fully squash it, the next step is usually 2000ms (the global default), but let’s see what 1000 does first.

pure forge
#

Results are in.

Finding: The cache‑trace shows the same message ID appearing multiple times within a single model run (2–8 copies). That confirms the duplicates are being injected before the model call — i.e., it’s queue/replay, not Discord sending multiple events.

State now:
Diagnostics trace disabled (reverted)
All Discord bots re‑enabled
historyLimit still 0

Next fix (recommended): apply inbound debounce for Discord to coalesce retries.
I suggest messages.inbound.byChannel.discord = 1000 (1s). It will drop rapid duplicates; only risk is if you send two messages within a second, they might merge.

Want me to apply that now and test?

grand craterBOT
#

That cache-trace result (same Discord message_id duplicated inside a single run) is extremely strong evidence of a framework bug / replay path, not “you accidentally enabled 3 bots”.

Inbound debounce is a reasonable mitigation to try anyway, because it can prevent rapid duplicate deliveries from ever reaching the session/queue layer.

Yes — apply it (with the correct key) and test

Use:

openclaw config set messages.inbound.byChannel.discord 1000 --json
openclaw gateway restart

Then /new and do a single-message test.

Tradeoff is real (messages sent within 1s from the same sender+channel can coalesce), but as a stopgap it’s fine.

Also: please file a GitHub issue (this shouldn’t be “fixed” by debounce)

#

“Same MessageSid appears 2–8x within one model run” is not expected behavior. Debounce may hide it, but we should still get it fixed upstream.

Issue link: https://github.com/openclaw/openclaw/issues
Include (redacted):

  • OpenClaw version (2026.3.2)
  • confirmation /new doesn’t change it
  • the cache-trace snippet showing the same message_id repeated within one run
  • whether messages.inbound.byChannel.discord=1000 reduces it

If you want, paste just the before/after counts from your cache-trace for one message id (e.g. “was 6 copies, now 1 copy”) after applying debounce.

pure forge
#

looks liek debounce "fixed " it