openclaw - 💡(How to fix) Fix [Bug]: image_generate still duplicate-sends Discord attachments after terminal guard [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…

This is a follow-up to #87989 because GitHub will not let me reopen that issue after it was closed as completed. The original issue is not fixed in the latest beta.

After updating the affected Discord bot instance to 2026.5.28-beta.1 (84fd629), a single successful image_generate completion still sent the same generated Discord attachment 12 times.

Root Cause

This is a follow-up to #87989 because GitHub will not let me reopen that issue after it was closed as completed. The original issue is not fixed in the latest beta.

Fix Action

Fixed

Code Example

OpenClaw 2026.5.28-beta.1 (84fd629)
Service: systemd user (enabled)
File logs: /tmp/openclaw/openclaw-2026-05-29.log
Install method: npm global
Gateway: systemd user service
Model for requester/completion session: ollama/glm-5.1:cloud
Image provider/model from completion event: google/gemini-3.1-flash-image-preview

---

Run: image_generate:5e66cfd7-9cff-4edd-86b5-85d5aec8e2fe:ok
Session key: agent:main:discord:channel:1507887702379335791
Media path: ~/.openclaw/media/tool-image-generation/image-1---34799bf3-36d1-462a-8e08-3490a7e58a28.jpg
Discord attachment filename: image-1---34799bf3-36d1-462a-8e08-3490a7e58a28.jpg
Image size: 1197745 bytes, 1024x1024 JPEG

Requester session JSONL:
  message tool calls with that exact path: 12
  successful message tool results: 12
  delivery mirror idempotency keys: 12

Public Discord channel read:
  visible posts with that exact attachment filename: 12

---

01. 2026-05-29T10:40:36.989Z -> 1509869060245164055; routeKeys=channel; call=call_ulah6cgi
02. 2026-05-29T10:40:45.759Z -> 1509869098979561564; routeKeys=channel; call=call_ndkp55eb
03. 2026-05-29T10:40:53.712Z -> 1509869133053952060; routeKeys=channel; call=call_rl6o2078
04. 2026-05-29T10:41:00.283Z -> 1509869161067577508; routeKeys=target; call=call_fgt36hia
05. 2026-05-29T10:41:07.861Z -> 1509869192646492310; routeKeys=channel; call=call_94wri2z2
06. 2026-05-29T10:41:13.570Z -> 1509869216399097877; routeKeys=channel; call=call_jbqbwmkg
07. 2026-05-29T10:41:20.524Z -> 1509869244219785326; routeKeys=channel; call=call_uqiogzbp
08. 2026-05-29T10:41:25.994Z -> 1509869268496289884; routeKeys=channel; call=call_ljup701l
09. 2026-05-29T10:41:35.900Z -> 1509869305628463204; routeKeys=channel; call=call_1teg1h4j
10. 2026-05-29T10:41:41.837Z -> 1509869335076802711; routeKeys=channel; call=call_jz16jss4
11. 2026-05-29T10:41:59.827Z -> 1509869410498646137; routeKeys=channel; call=call_oqmy5de6
12. 2026-05-29T10:42:13.597Z -> 1509869466987794512; routeKeys=channel+target; call=call_qepozibv

---

The image has already been sent to the channel (multiple times, unfortunately — I was looping again). I will NOT send it again.
MEDIA:~/.openclaw/media/tool-image-generation/image-1---34799bf3-36d1-462a-8e08-3490a7e58a28.jpg

---

if (!isMessageToolSendActionName(args.action) || hasExplicitMessageRoute(args)) {
  return false;
}

---

const tryGeneratedMediaDirectDelivery = async (announceResponse?: unknown) => {
  if (requesterActivity.isActive && !activeRequesterWakeFailed) {
    return undefined;
  }
  ...
};

const completionSourceReplyDeliveryMode = requiresMessageToolDelivery
  ? "message_tool_only"
  : undefined;

const wakeOutcome = await resolveActiveWakeWithRetries(
  requesterActivity.sessionId,
  params.triggerMessage,
  wakeOptions,
  params.signal,
);
RAW_BUFFERClick to expand / collapse

Bug type

Behavior bug (incorrect output/state without crash)

Beta release blocker

No

Summary

This is a follow-up to #87989 because GitHub will not let me reopen that issue after it was closed as completed. The original issue is not fixed in the latest beta.

After updating the affected Discord bot instance to 2026.5.28-beta.1 (84fd629), a single successful image_generate completion still sent the same generated Discord attachment 12 times.

Steps to reproduce

  1. Run a Discord channel agent on OpenClaw 2026.5.28-beta.1.
  2. Ask the agent to generate an image for the current channel.
  3. Wait for the background image_generate:<taskId>:ok completion wake to route back to the requester session.
  4. Observe repeated message.send calls with the same generated media path and different captions.

Expected behavior

A successful image_generate completion should deliver each generated attachment exactly once to the original chat, then stop.

Historical message-tool calls, explicit route fields, or requester-session context should not be able to cause repeated delivery of the same completion artifact.

Actual behavior

One image_generate completion delivered the same generated JPEG 12 times to the same Discord channel. The run eventually stopped, so this is bounded duplicate delivery, not an infinite Discord retry loop.

Environment

OpenClaw 2026.5.28-beta.1 (84fd629)
Service: systemd user (enabled)
File logs: /tmp/openclaw/openclaw-2026-05-29.log
Install method: npm global
Gateway: systemd user service
Model for requester/completion session: ollama/glm-5.1:cloud
Image provider/model from completion event: google/gemini-3.1-flash-image-preview

Reproduction evidence

Run: image_generate:5e66cfd7-9cff-4edd-86b5-85d5aec8e2fe:ok
Session key: agent:main:discord:channel:1507887702379335791
Media path: ~/.openclaw/media/tool-image-generation/image-1---34799bf3-36d1-462a-8e08-3490a7e58a28.jpg
Discord attachment filename: image-1---34799bf3-36d1-462a-8e08-3490a7e58a28.jpg
Image size: 1197745 bytes, 1024x1024 JPEG

Requester session JSONL:
  message tool calls with that exact path: 12
  successful message tool results: 12
  delivery mirror idempotency keys: 12

Public Discord channel read:
  visible posts with that exact attachment filename: 12

Receipt summary:

01. 2026-05-29T10:40:36.989Z -> 1509869060245164055; routeKeys=channel; call=call_ulah6cgi
02. 2026-05-29T10:40:45.759Z -> 1509869098979561564; routeKeys=channel; call=call_ndkp55eb
03. 2026-05-29T10:40:53.712Z -> 1509869133053952060; routeKeys=channel; call=call_rl6o2078
04. 2026-05-29T10:41:00.283Z -> 1509869161067577508; routeKeys=target; call=call_fgt36hia
05. 2026-05-29T10:41:07.861Z -> 1509869192646492310; routeKeys=channel; call=call_94wri2z2
06. 2026-05-29T10:41:13.570Z -> 1509869216399097877; routeKeys=channel; call=call_jbqbwmkg
07. 2026-05-29T10:41:20.524Z -> 1509869244219785326; routeKeys=channel; call=call_uqiogzbp
08. 2026-05-29T10:41:25.994Z -> 1509869268496289884; routeKeys=channel; call=call_ljup701l
09. 2026-05-29T10:41:35.900Z -> 1509869305628463204; routeKeys=channel; call=call_1teg1h4j
10. 2026-05-29T10:41:41.837Z -> 1509869335076802711; routeKeys=channel; call=call_jz16jss4
11. 2026-05-29T10:41:59.827Z -> 1509869410498646137; routeKeys=channel; call=call_oqmy5de6
12. 2026-05-29T10:42:13.597Z -> 1509869466987794512; routeKeys=channel+target; call=call_qepozibv

The requester session then stopped only after the model noticed it had looped:

The image has already been sent to the channel (multiple times, unfortunately — I was looping again). I will NOT send it again.
MEDIA:~/.openclaw/media/tool-image-generation/image-1---34799bf3-36d1-462a-8e08-3490a7e58a28.jpg

Why #83022 / the terminal guard is not sufficient

The closure on #87989 pointed to the message-tool terminal guard as already fixing this. That guard exists in current main and in the tested beta, but it does not cover this reproduced path.

Current main's message-tool-terminal.ts returns false for explicit route sends:

if (!isMessageToolSendActionName(args.action) || hasExplicitMessageRoute(args)) {
  return false;
}

Every duplicate send in this reproduction used an explicit route key: channel, target, or both. So the terminal guard is present, but it deliberately does not terminate the duplicate sends seen here.

Completion delivery path still delegates to the requester LLM first

Current main's generated-media completion path still makes direct generated-media delivery fallback-only while the requester session is active:

const tryGeneratedMediaDirectDelivery = async (announceResponse?: unknown) => {
  if (requesterActivity.isActive && !activeRequesterWakeFailed) {
    return undefined;
  }
  ...
};

const completionSourceReplyDeliveryMode = requiresMessageToolDelivery
  ? "message_tool_only"
  : undefined;

const wakeOutcome = await resolveActiveWakeWithRetries(
  requesterActivity.sessionId,
  params.triggerMessage,
  wakeOptions,
  params.signal,
);

That means successful generated-media delivery is still handed to an LLM wake first, with direct delivery only as fallback. The current terminal guard only handles a subset of message-tool sends after delivery; it does not enforce artifact-level idempotency.

Impact and severity

Severity: Medium.

This does not crash the gateway, but it spams channels, repeats uploads, wastes tool/provider work, and makes image completion delivery unreliable.

Suggested fix

Either:

  1. Prefer deterministic direct delivery for generated-media completions when expected media URLs are present, before waking the requester LLM; or
  2. Add a hard idempotency guard keyed by image_generate:<taskId>:ok + target + mediaUrls, and stop/ignore any later send attempts for the same artifact.

Draft PR #87991 implements the direct-first approach.

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

A successful image_generate completion should deliver each generated attachment exactly once to the original chat, then stop.

Historical message-tool calls, explicit route fields, or requester-session context should not be able to cause repeated delivery of the same completion artifact.

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]: image_generate still duplicate-sends Discord attachments after terminal guard [1 pull requests]