#21230: Fix [Bug]: Discord attachments silently missing (Fixes #19956)
size: M
Cluster:
Media Handling Improvements
## Summary
When sending Discord attachments via message.send, OpenClaw returns success (ok: true, messageId), but the resulting Discord message contains no attachment object. Only text content appears.
## Environment
- OpenClaw versions tested: 2026.2.15, 2026.2.17
- Channel plugin: Discord
- Host: Linux, Node 22.x
## Expected behavior
The message should include a real downloadable attachment.
## Actual behavior
- API/tool result indicates success (ok: true, valid messageId).
- Message content is posted.
- message.read for that messageId shows: attachments: []
## Minimal reproduction
1. Send tiny attachment via message.send using buffer payload:
- filename: test.txt
- buffer: <base64 text>
- contentType: text/plain
2. Observe tool result: success with messageId.
3. Read back message with message.read around that messageId.
4. Observe empty attachments array.
## Impact
- Export workflows relying on file attachments are broken.
- Users receive text-only messages where files are expected.
## Validation
Verified bot permissions include AttachFiles. Reproduced in multiple channels/threads. Confirmed on clean, isolated gateway instance.
<!-- greptile_comment -->
<h3>Greptile Summary</h3>
Added support for `buffer` parameter in message.send action by materializing base64-encoded buffers to temporary files before passing them to the Discord send pipeline.
**Key changes:**
- Reads `buffer` parameter (base64-encoded) from params
- Decodes buffer and writes to temp file in OpenClaw tmp directory
- Uses `filename` and `contentType` params to determine appropriate file name/extension
- Adds temp file path to `mergedMediaUrls` array for delivery
- Cleanup via try/finally ensures temp file is deleted after send completes
- Added comprehensive test coverage for buffer materialization and cleanup
The fix correctly integrates with the existing media delivery pipeline in `deliver.ts:556-568`, which iterates through `mediaUrls` and sends each via `handler.sendMedia()`. Previously, buffer attachments were being ignored because they weren't materialized to files.
<h3>Confidence Score: 5/5</h3>
- This PR is safe to merge with minimal risk
- The implementation is clean and well-tested. It properly handles buffer-to-file materialization with appropriate error handling and cleanup. The code integrates correctly with the existing media delivery pipeline without breaking changes. Test coverage includes both the happy path and edge cases like dryRun mode.
- No files require special attention
<sub>Last reviewed commit: 6eb5237</sub>
<!-- greptile_other_comments_section -->
<sub>(2/5) Greptile learns from your feedback when you react with thumbs up/down!</sub>
<!-- /greptile_comment -->
Most Similar PRs
#20913: fix: intercept Discord embed images to enforce mediaMaxMb
by MumuTW · 2026-02-19
81.4%
#20479: fix(slack): keep replies flowing for oversized file uploads
by olyashok · 2026-02-19
78.9%
#20488: fix(discord): pass mediaLocalRoots to sendMessageDiscord
by olyashok · 2026-02-19
78.7%
#22942: fix(slack): parse generic attachment text for inbound events
by danielalkurdi · 2026-02-21
78.6%
#15095: fix(slack): process all file attachments instead of only the first
by Lar000ki · 2026-02-13
78.4%
#22113: feat: support non-image file attachments in webchat chat.send
by Kt-L · 2026-02-20
77.6%
#17316: fix: ack reaction not removed when block streaming is enabled (Tele...
by czmathew · 2026-02-15
77.3%
#10027: Mattermost: fix attachment downloads (GET + private-network hosts)
by transportrefer · 2026-02-06
77.3%
#15914: feat: add messages.suppressMediaPlaceholders config option
by Shuai-DaiDai · 2026-02-14
76.9%
#20480: feat(slack): extract and surface attachment notes in messages
by olyashok · 2026-02-19
75.8%