`--channels` fails to deliver messages when the plugin is loaded via `--plugin-dir` instead of `enabledPlugins` (origin mismatch: "inline" vs "marketplace")

Open 💬 0 comments Opened Jul 13, 2026 by CalistoDeOliveira

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?

This is a follow-up to #42413 (multiple sessions loading the Telegram channel plugin simultaneously, SIGTERM poller-theft). We hit exactly that bug: a plugin enabled globally in enabledPlugins gets loaded by every claude session on the machine, not just the one launched with --channels, and the plugin's own MCP server (telegram@claude-plugins-official in our case) evicts any prior poller via unconditional SIGTERM on startup — so opening any ordinary claude session steals the channel session's poller. The documented workaround for that class of bug (see anthropics/claude-plugins-official#1075) is: disable the plugin globally, and load it only for the dedicated session via --plugin-dir. We did exactly that — and it exposes a second, distinct bug, which is what this issue is about.

With the plugin removed from enabledPlugins and loaded via:

claude --channels plugin:telegram@claude-plugins-official --plugin-dir C:\Users\<user>\.claude\plugins\cache\claude-plugins-official\telegram\0.0.6

the full process chain comes up correctly (claude -> bun run -> bun.exe server.ts), the Telegram poller correctly consumes messages from the Bot API (getWebhookInfo shows pending_update_count: 0), but the message is never delivered to the host session. No error is written back to the plugin's server.ts (the mcp.notification({ method: 'notifications/claude/channel', ... }) call is fire-and-forget with no ack), so the plugin has no way to know delivery failed.

With --debug --debug-file <path> (the only combination of debug flags that doesn't itself break --channels — redirecting stdout/stderr directly causes an unrelated crash: Error: Input must be provided either through stdin or as a prompt argument when using --print), we found the actual reason logged once at connection time:

MCP server "plugin:telegram:telegram": Channel notifications skipped: you asked for plugin:telegram@claude-plugins-official but the installed telegram plugin is from inline

So --channels plugin:telegram@claude-plugins-official expects the plugin's origin metadata to say marketplace (or otherwise match the reference string), but --plugin-dir always registers the plugin with origin inline, regardless of whether the directory it points to is byte-identical to the marketplace-installed copy. The host decides not to subscribe to that MCP server's channel notifications at all, once, silently, with no retry for the rest of the session.

Net effect: there is currently no working combination of flags that gives us both (a) isolation from other concurrent claude sessions stealing the plugin's poller (the #42413 bug), and (b) actual message delivery to the --channels session — because (a) requires not using global enabledPlugins, and (b) currently requires using it, since --plugin-dir breaks the origin match. We ended up reverting to global enabledPlugins and mitigating the poller-theft bug with an external watchdog script instead, since that's the only way to get a working system today.

Suggested fix: either (1) --channels plugin:X@marketplace should match against a plugin loaded via --plugin-dir when the resolved path is identical to (or otherwise equivalent to) the marketplace-installed plugin's path, or (2) --channels should accept an inline-origin plugin as satisfying a plugin:X@marketplace reference when no ambiguity exists, or at minimum (3) the mismatch should produce a visible error/warning, not just a debug-log-only skip — today this fails completely silently from the operator's perspective (no error in Telegram, no error in the plugin's own logs, nothing without --debug-file).

What Should Happen?

A --channels session launched with --plugin-dir pointing at an already-installed marketplace plugin should still receive channel messages from that plugin's MCP server, the same way it does when the plugin is enabled via enabledPlugins.

Error Messages/Logs

Environment: Windows 11, Claude Code 2.1.207, plugin telegram@claude-plugins-official v0.0.6.

Broken: claude --channels plugin:telegram@claude-plugins-official --plugin-dir <path-to-installed-plugin-dir>
Working (but reintroduces the SIGTERM poller-theft bug): claude --channels plugin:telegram@claude-plugins-official with the plugin enabled in enabledPlugins

Relevant debug log line (via --debug --debug-file):
MCP server "plugin:telegram:telegram": Channel notifications skipped: you asked for plugin:telegram@claude-plugins-official but the installed telegram plugin is from inline

Happy to provide the full --debug-file log or reproduce with more detail if useful.

Steps to Reproduce

  1. Install the telegram@claude-plugins-official plugin (or any plugin usable with --channels).
  2. Remove it from enabledPlugins in settings.json (needed to avoid the SIGTERM poller-theft bug from another concurrent session, see anthropics/claude-plugins-official#1075/#2229).
  3. Launch a dedicated channel session instead, loading the plugin only for that session:

claude --channels plugin:telegram@claude-plugins-official --plugin-dir <path-to-the-same-installed-plugin-directory>

  1. Confirm the process chain comes up (claude -> bun run -> bun.exe server.ts) and the plugin's poller is consuming messages from the Telegram Bot API (e.g. getWebhookInfo shows pending_update_count: 0).
  2. Send a message to the bot from Telegram.
  3. Observe: no reply, no error, message is never delivered to the host session. Run with --debug --debug-file <path> to see the actual reason logged once at connection time: "Channel notifications skipped: you asked for plugin:telegram@claude-plugins-official but the installed telegram plugin is from inline".

Expected: message delivered and processed same as when the plugin is loaded via enabledPlugins instead of --plugin-dir.

Claude Model

None

Is this a regression?

Yes, this worked in a previous version

Last Working Version

_No response_

Claude Code Version

2.1.207 (Claude Code)

Platform

Anthropic API

Operating System

Windows

Terminal/Shell

PowerShell

Additional Information

_No response_

View original on GitHub ↗