openclaw - 💡(How to fix) Fix [Bug] Stale images re-hydrated from `[media attached: ...]` text persisting in message history [4 comments, 2 participants]

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…
GitHub stats
openclaw/openclaw#71868Fetched 2026-04-26 05:07:19
View on GitHub
Comments
4
Participants
2
Timeline
7
Reactions
0
Author
Participants
Timeline (top)
commented ×4labeled ×2closed ×1

detectAndLoadPromptImages() re-loads image files by parsing [media attached: <path>] markers out of effectivePrompt. These markers are injected into message body text at ingest time and persist verbatim in conversation history and in any downstream store that captures prompt text (e.g. long-term memory plugins). pruneProcessedHistoryImages() strips only image-type content blocks from history; it does not scrub the text markers. As a result, any historical [media attached: ...] string that finds its way back into effectivePrompt (via recalled memory context, agent replay, or tool output) gets re-attached as a fresh image on the current turn.

Root Cause

Two places inject marker text into message body:

  • channel.runtime-DlujcGUq.js:3260 — Tlon handler:
    attachments.map((a) => `[media attached: ${a.path} (${a.contentType}) | ${a.path}]`).join("\n") + "\n" + messageText
  • attachment-normalize-ByqTaJZf.js:206 — gateway interceptor for offloaded media:
    updatedMessage += `\n[media attached: ${mediaRef}]`  // mediaRef = `media://inbound/${savedMedia.id}`

pruneProcessedHistoryImages() in selection-DmkxuIQC.js:5203 only removes image-type content blocks; it does not rewrite text content.

detectImageReferences() / detectAndLoadPromptImages() in images-BOQBeEoo.js use MEDIA_ATTACHED_PATTERN = /\[media attached(?:\s+\d+\/\d+)?:\s*([^\]]+)\]/gi against params.prompt (= effectivePrompt) — with no scoping to the current turn.

Fix Action

Fix / Workaround

Workaround (local)

Memory plugins can strip [media attached: ...] and media://inbound/<id> from any text they inject back into the prompt. Patched locally in memory-openviking (see text-utils.ts stripMediaRefs).

Code Example

attachments.map((a) => `[media attached: ${a.path} (${a.contentType}) | ${a.path}]`).join("\n") + "\n" + messageText

---

updatedMessage += `\n[media attached: ${mediaRef}]`  // mediaRef = `media://inbound/${savedMedia.id}`
RAW_BUFFERClick to expand / collapse

[Bug] Stale images re-hydrated from [media attached: ...] text persisting in message history

Summary

detectAndLoadPromptImages() re-loads image files by parsing [media attached: <path>] markers out of effectivePrompt. These markers are injected into message body text at ingest time and persist verbatim in conversation history and in any downstream store that captures prompt text (e.g. long-term memory plugins). pruneProcessedHistoryImages() strips only image-type content blocks from history; it does not scrub the text markers. As a result, any historical [media attached: ...] string that finds its way back into effectivePrompt (via recalled memory context, agent replay, or tool output) gets re-attached as a fresh image on the current turn.

Impact

  • Assistant comments on stale screenshots/photos as if they were just sent.
  • Model context silently grows with re-ingested image tokens (cost + latency).
  • Long-term memory plugins poison themselves: captured "user text" contains raw file paths that come back as attachments on every later recall.

Reproduction

  1. Send a message with an attached image. OpenClaw (Tlon handler at channel.runtime-DlujcGUq.js:3260 or gateway interceptor at attachment-normalize-ByqTaJZf.js:206) injects [media attached: /.../file.jpg (image/jpeg) | /.../file.jpg] into the message body text.
  2. Wait until the image is >3 completed turns old so pruneProcessedHistoryImages() removes the image content block. The marker text remains in message body text.
  3. Use any mechanism that lifts that text back into effectivePrompt on a later turn — e.g. a memory plugin's "recalled memories" block, a summarization that quotes old messages, or a tool that replays history.
  4. Observe that detectAndLoadPromptImages() in images-BOQBeEoo.js re-reads the file and attaches it as a new image.

Root Cause

Two places inject marker text into message body:

  • channel.runtime-DlujcGUq.js:3260 — Tlon handler:
    attachments.map((a) => `[media attached: ${a.path} (${a.contentType}) | ${a.path}]`).join("\n") + "\n" + messageText
  • attachment-normalize-ByqTaJZf.js:206 — gateway interceptor for offloaded media:
    updatedMessage += `\n[media attached: ${mediaRef}]`  // mediaRef = `media://inbound/${savedMedia.id}`

pruneProcessedHistoryImages() in selection-DmkxuIQC.js:5203 only removes image-type content blocks; it does not rewrite text content.

detectImageReferences() / detectAndLoadPromptImages() in images-BOQBeEoo.js use MEDIA_ATTACHED_PATTERN = /\[media attached(?:\s+\d+\/\d+)?:\s*([^\]]+)\]/gi against params.prompt (= effectivePrompt) — with no scoping to the current turn.

Proposed Fix

When pruneProcessedHistoryImages() drops the image content block for an old turn, also rewrite any [media attached: ...] and media://inbound/<id> marker text in the same message's text blocks to a non-matching placeholder (e.g. [media attached — already processed]), so later passes through MEDIA_ATTACHED_PATTERN won't re-match.

Alternative / complementary: have detectAndLoadPromptImages() consult a per-turn allowlist of media refs the model has already seen, and skip any ref older than N turns.

Workaround (local)

Memory plugins can strip [media attached: ...] and media://inbound/<id> from any text they inject back into the prompt. Patched locally in memory-openviking (see text-utils.ts stripMediaRefs).

Environment

  • OpenClaw v2026.4.22
  • Node v25.9.0
  • macOS 25.4.0 arm64

extent analysis

TL;DR

Modify pruneProcessedHistoryImages() to rewrite [media attached: ...] markers in message text to prevent re-loading of stale images.

Guidance

  • Identify and update the pruneProcessedHistoryImages() function in selection-DmkxuIQC.js:5203 to rewrite [media attached: ...] markers in message text blocks to a non-matching placeholder.
  • Consider implementing a per-turn allowlist of media refs in detectAndLoadPromptImages() to skip older refs.
  • Memory plugins can strip [media attached: ...] and media://inbound/<id> from injected text as a temporary workaround.
  • Review the MEDIA_ATTACHED_PATTERN regex in images-BOQBeEoo.js to ensure it correctly matches the rewritten markers.

Example

// Example rewrite of pruneProcessedHistoryImages()
function pruneProcessedHistoryImages(message) {
  // Remove image content blocks
  // ...
  // Rewrite [media attached: ...] markers in message text
  message.text = message.text.replace(/\[media attached: ([^\]]+)\]/g, '[media attached — already processed]');
  return message;
}

Notes

The proposed fix requires updating the pruneProcessedHistoryImages() function, which may have unintended consequences on other parts of the system. Thorough testing is recommended.

Recommendation

Apply the proposed fix by modifying pruneProcessedHistoryImages() to rewrite [media attached: ...] markers, as it directly addresses the root cause of the issue.

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

openclaw - 💡(How to fix) Fix [Bug] Stale images re-hydrated from `[media attached: ...]` text persisting in message history [4 comments, 2 participants]