#10027: Mattermost: fix attachment downloads (GET + private-network hosts)
docs
channel: mattermost
stale
Cluster:
Mattermost and Zulip Enhancements
## Summary
Fixes Mattermost inbound attachments sometimes not showing up in OpenClaw.
## What changed
- Mattermost plugin now downloads `/api/v4/files/{file_id}` via `GET` directly (streamed + max-bytes enforced) instead of the generic `fetchRemoteMedia()` path.
- Some Mattermost servers return `404` to `HEAD /api/v4/files/{file_id}` even when `GET` succeeds, which can cause false “missing attachment” behavior.
- This also avoids attachment downloads being blocked when the configured Mattermost host resolves to private/VPN/Tailscale IPs.
- Adds a fallback: if a WebSocket `posted` event omits `file_ids` entirely, the plugin refetches the post via `GET /api/v4/posts/{post_id}` to discover attachments.
- Declares runtime deps for the plugin (`ws`, `zod`) so npm-installed plugins work outside the monorepo.
## Notes
- Downloads are still constrained by `channels.*.mediaMaxBytes` via `resolveChannelMediaMaxBytes`.
## Testing
- `pnpm vitest run --config vitest.extensions.config.ts extensions/mattermost/src/channel.test.ts`
- `pnpm tsgo`
<!-- greptile_comment -->
<h2>Greptile Overview</h2>
<h3>Greptile Summary</h3>
This PR updates the Mattermost channel plugin’s inbound attachment handling to avoid relying on `HEAD /api/v4/files/{id}` (some servers return 404 to HEAD), instead downloading attachments via authenticated `GET` with a max-bytes limit and saving them through the existing media pipeline. It also adds a fallback to refetch posts over REST when WebSocket `posted` events omit `file_ids`, and declares runtime dependencies (`ws`, `zod`) in the plugin package so npm installs work outside the monorepo.
Primary behavior changes are localized to `extensions/mattermost/src/mattermost/monitor.ts` (download path + post refetch) and `extensions/mattermost/src/mattermost/client.ts` (new `fetchMattermostPost`).
<h3>Confidence Score: 4/5</h3>
- This PR is likely safe to merge once error reporting is tightened to avoid leaking server response bodies.
- Changes are straightforward and localized (switching to GET downloads with byte limits and adding a post-refetch fallback). Main concern is that thrown errors may include full HTTP response bodies, which can surface sensitive server details in logs depending on deployment.
- extensions/mattermost/src/mattermost/monitor.ts
<!-- 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
#11086: fix(mattermost): allow private network for inbound media download
by oskarmodig · 2026-02-07
78.9%
#10394: feat(mattermost): add image attachment support for inbound messages
by mithril-logic · 2026-02-06
78.2%
#21230: Fix [Bug]: Discord attachments silently missing (Fixes #19956)
by vasujain00 · 2026-02-19
77.3%
#10763: docs(mattermost): marketplace-ready README, CHANGELOG, npm listing
by ProofOfReach · 2026-02-06
76.5%
#15051: feat: Zulip channel plugin with concurrent message processing
by FtlC-ian · 2026-02-12
75.8%
#12257: fix(mattermost): default table mode to 'off' for native Markdown re...
by mcaxtr · 2026-02-09
75.4%
#20913: fix: intercept Discord embed images to enforce mediaMaxMb
by MumuTW · 2026-02-19
75.1%
#22942: fix(slack): parse generic attachment text for inbound events
by danielalkurdi · 2026-02-21
74.9%
#9319: [Swarm] [Mattermost] WebSocket disconnects with "client si
by swarmagents · 2026-02-05
74.8%
#12468: feat(mattermost): add read, search, and channel-list actions
by adamsbytes · 2026-02-09
74.7%