[BUG] Discord plugin: fire-and-forget mcp.notification() silently drops inbound messages on Windows
Preflight Checklist
- [x] I have searched existing issues and this hasn't been reported yet
- [x] This is a single bug report (please file separate reports for different bugs)
- [x] I am using the latest version of Claude Code
What's Wrong?
When running claude --channels plugin:discord@claude-plugins-official on Windows 11, the Discord bot connects successfully (pairing works, bot sends codes and confirmation), but post-pairing inbound messages are never delivered to the Claude Code session. The bot shows typing indicators and ack reactions, confirming the gate passes and handleInbound() runs — but the mcp.notification() at server.ts:868 silently fails to deliver.
Related to #36837 (Linux gateway issue) but distinct root cause on Windows.
Root Cause Analysis
Traced through server.ts and identified two issues:
1. Fire-and-forget notification (server.ts:868)
mcp.notification({
method: 'notifications/claude/channel',
params: { content, meta: { ... } },
}).catch(err => {
process.stderr.write(`discord channel: failed to deliver inbound to Claude: ${err}\n`)
})
The notification is not awaited. On Windows, the stdio pipe buffer behavior differs from Unix — writes can silently fail if Claude Code is mid-turn or the pipe buffer is under pressure. No retry, no queue, no success logging. If the write fails without throwing (partial write / buffer full), the .catch() never fires and the message is silently lost.
2. Channel cache staleness (server.ts:392) — already identified in #36837 comments
client.channels.fetch(id) without { force: true } returns stale cached partials after idle, causing recipientId to be undefined and the allowlist check to fail on outbound replies.
Evidence
- Pairing works (bot sends code + confirmation via direct
msg.reply()) ✅ - Gate passes for allowlisted user (typing indicator + ack reaction fire) ✅
mcp.notification()called but message never appears in Claude session ❌- No stderr errors logged (the
.catch()doesn't fire) ❌ - Manual
fetch_messagestool call retrieves messages correctly ✅
The fact that fetch_messages (synchronous tool request) works but mcp.notification() (async push) doesn't confirms the issue is in the notification delivery path, not the gateway or access control.
Suggested Fix
// server.ts:868 — await + retry instead of fire-and-forget
- mcp.notification({
+ await notifyWithRetry(mcp, {
method: 'notifications/claude/channel',
params: { ... },
- }).catch(err => {
- process.stderr.write(`...`)
})
// Add retry helper
+async function notifyWithRetry(server, payload, maxRetries = 3) {
+ for (let attempt = 1; attempt <= maxRetries; attempt++) {
+ try {
+ await server.notification(payload)
+ return
+ } catch (err) {
+ process.stderr.write(`notification attempt ${attempt}/${maxRetries} failed: ${err}\n`)
+ if (attempt < maxRetries) await new Promise(r => setTimeout(r, 300 * attempt))
+ }
+ }
+}
// server.ts:392 — force-fetch to avoid stale cache (per #36837 comments)
- const ch = await client.channels.fetch(id)
+ const ch = await client.channels.fetch(id, { force: true })
Claude Code Version
Latest (Claude MAX subscription)
Platform
Claude MAX
Operating System
Windows 11 Home 10.0.26200
Terminal/Shell
bash (Git Bash)
Additional Information
- Plugin version: discord@claude-plugins-official 0.0.4
- discord.js ^14.14.0
- Bun runtime
- Applied the fix locally and testing
This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗