#15770: fix: prevent phantom <media:unknown> messages from Signal protocol events
size: XS
Cluster:
Signal Plugin Enhancements
## Problem
Users receive phantom `<media:unknown>` messages on Signal that they didn't send. These appear as real messages from the bot, causing confusion (and unwanted notification chimes on phone, watch, and desktop).
## Root Cause
When Signal delivers protocol-level events (profile key updates, group metadata changes, disappearing message timer changes), signal-cli may represent them as messages with an `attachments` array where entries have no `contentType`.
`mediaKindFromMime()` returned `"unknown"` for null/undefined mime types. Since `"unknown"` is truthy, the Signal event handler's `if (kind)` check passed and produced `<media:unknown>` placeholders. These became the message body and were delivered to users as phantom messages.
## Fix
Return `undefined` instead of `"unknown"` from `mediaKindFromMime()` when the mime type is null/undefined. This causes downstream `if (kind)` guards to correctly skip placeholder generation, and existing `if (!bodyText) return` checks filter out the empty messages.
The `"unknown"` return value is preserved for unrecognized but **present** mime types (e.g. `application/x-custom`), which is correct behavior.
## Impact
- **Signal**: Phantom `<media:unknown>` messages no longer delivered
- **All channels**: Consistent behavior — missing mime ≠ unknown mime
- **No breaking changes**: All callers already use truthy checks or switch/default patterns that handle `undefined` gracefully
## Testing
Verified all callers of `mediaKindFromMime` across Signal, Telegram, iMessage, Discord, and web media handlers — all use `if (kind)`, switch/default, or optional chaining patterns that correctly handle `undefined`.
<!-- greptile_comment -->
<h2>Greptile Overview</h2>
<h3>Greptile Summary</h3>
This change updates `mediaKindFromMime()` to return `undefined` (instead of `"unknown"`) when the MIME type is missing, so downstream placeholder generation can correctly skip attachments that lack `contentType` (e.g., Signal protocol-level events).
The main correctness concern is that not all wrappers/callers were updated for the new return type: `src/media/mime.ts` still exposes `kindFromMime(): MediaKind` while directly returning the now-optional result. That creates a type contract break and can leak `undefined` into code paths that assume a concrete `MediaKind`.
<h3>Confidence Score: 3/5</h3>
- This PR is close to safe but has a concrete type/contract break that should be fixed before merging.
- The behavioral change in `mediaKindFromMime` looks targeted and aligns with the described Signal issue, but at least one wrapper (`kindFromMime`) still claims to return a non-optional `MediaKind` while forwarding a now-optional value. That’s likely to fail TS compilation or lead to incorrect assumptions in callers.
- src/media/mime.ts
<sub>Last reviewed commit: 6a573c5</sub>
<!-- greptile_other_comments_section -->
<!-- /greptile_comment -->
Most Similar PRs
#9757: fix(signal): exclude "unknown" media kind from placeholder generation
by leszekszpunar · 2026-02-05
84.3%
#15853: feat: add option to suppress media placeholder text
by MisterGuy420 · 2026-02-14
74.9%
#11160: Media: add missing audio MIME-to-extension mappings (aac, flac, opu...
by lailoo · 2026-02-07
74.9%
#14794: fix: parse inline MEDIA: tokens in agent replies
by explainanalyze · 2026-02-12
74.8%
#18811: fix(media): require file extension for ambiguous MEDIA: path detection
by aldoeliacim · 2026-02-17
74.3%
#21276: fix(telegram): stabilize partial finalization and MEDIA dedupe (AI-...
by HOYALIM · 2026-02-19
74.2%
#22540: fix(signal): preserve original filename in outbound attachments
by lailoo · 2026-02-21
74.2%
#22434: feat(telegram): support sending original quality images
by godenjan · 2026-02-21
73.9%
#7454: fix: skip UTF-16 heuristic for audio/video/image MIME types (#7444)
by gavinbmoore · 2026-02-02
73.8%
#14057: feat(telegram): add ignoreMediaTypes config to skip specific inboun...
by pavelsamoylenko · 2026-02-11
73.7%