[BUG] Headless claude -p poisons global mcp-needs-auth-cache.json for the telegram channels plugin — subsequent --channels sessions silently never spawn their poller
Summary
One unrelated headless claude -p invocation on a machine silently disables all Telegram channel bots started in the following minutes, via the global ~/.claude/mcp-needs-auth-cache.json.
Mechanism:
- The telegram channels plugin (
plugin:telegram@claude-plugins-official) is installed user-wide. Real bots each run with their ownTELEGRAM_STATE_DIR(multi-bot isolation); the plugin's default state dir (~/.claude/channels/telegram) has no active bot token configured. - A headless
claude -p "ok"is run withoutTELEGRAM_STATE_DIRset. The plugin resolves its default state dir, finds no token, and Claude Code writes aplugin:telegram:telegramentry into the global~/.claude/mcp-needs-auth-cache.json. - Any
claude --channels plugin:telegram@claude-plugins-officialsession started while that cache entry is fresh — even withTELEGRAM_STATE_DIRpointing at a fully-configured state dir with a valid token — silently never spawns its Telegram poller (thebunchild). The session runs, registers.in_use, but never polls. No error or warning is surfaced anywhere. - The cache entry ages out after some minutes, after which restarts behave normally — which makes the failure look random/transient and very hard to attribute.
The cache is keyed by plugin/server name only, so a needs-auth verdict computed against one state dir (the unconfigured default) is applied to sessions using a different, fully-authorized state dir.
Environment
- Claude Code: 2.1.218
- Telegram plugin: 0.0.6 (
telegram@claude-plugins-official), installed user-wide - OS: Windows 11 Pro (10.0.26200)
- Setup: 3 channel bots, each launched with its own
TELEGRAM_STATE_DIR(own.envtoken +access.json); default state dir token intentionally commented out; a scheduled credential-refresh job runsclaude -p "ok"periodically (this was the poisoning trigger)
Steps to reproduce
- Install the telegram plugin user-wide. Leave the default state dir (
~/.claude/channels/telegram) without a valid bot token. - Prepare a working state dir, e.g.
~/.claude/channels/telegram-mybot, with a valid.envtoken +access.json. - Run
claude -p "ok"with noTELEGRAM_STATE_DIRin the environment. - Observe
~/.claude/mcp-needs-auth-cache.jsonnow contains a freshplugin:telegram:telegramentry. - Within the cache TTL, launch
TELEGRAM_STATE_DIR=~/.claude/channels/telegram-mybot claude --channels plugin:telegram@claude-plugins-official. - The session starts and registers
.in_use, but no poller process is spawned (nobunchild, nobot.pidwritten). Messages sent to the bot are never pulled. No error is shown. - Delete the cache entry (or wait for it to expire) and restart the channel session → poller spawns immediately and polling resumes.
Observed evidence (2026-07-24, ~11:07 local)
Supervisor watchdog log (checks each bot's claude session + its poller pid):
[2026-07-24 11:06:01] inbox: claude=pid 31284 age 5.9m | bot.pid=31460 wrote 11:00:07 -> ALIVE
[2026-07-24 11:06:01] missions: claude=pid 29172 age 5.9m | bot.pid=23332 wrote 11:00:07 -> ALIVE
[2026-07-24 11:06:01] kztrip: claude=pid 2932 age 5.9m | bot.pid=3480 wrote 11:00:07 -> ALIVE
[2026-07-24 11:09:01] inbox: claude=pid 18932 age 1.5m | bot.pid=31460 wrote 11:00:07 -> DEAD
[2026-07-24 11:09:01] missions: claude=pid 17524 age 1.5m | bot.pid=23332 wrote 11:00:07 -> DEAD
[2026-07-24 11:09:01] kztrip: claude=pid 28112 age 1.5m | bot.pid=3480 wrote 11:00:07 -> DEAD
All 3 bots were restarted at ~11:07:30 (right after the scheduled claude -p "ok"), and all 3 fresh sessions came up without a poller. The plugin:telegram:telegram timestamp in mcp-needs-auth-cache.json matched the claude -p run to the second. Removing the entry and recycling the channel sessions restored polling on all 3 bots immediately.
This root cause was only found after two earlier wrong theories, precisely because (a) nothing is logged/surfaced when the poller is skipped, and (b) the cache entry expires within minutes, so later manual restarts always worked.
Expected behavior
- A needs-auth verdict for a channels plugin should be scoped to the configuration it was computed against (the resolved state dir), not applied globally by plugin name to sessions using a different, fully-configured state dir.
- If a
--channelssession skips spawning its poller for any reason (including a needs-auth cache hit), that should be surfaced visibly in the session — a silent no-op bot is the worst failure mode for an unattended channel.
Suggested fixes
- Scope the needs-auth cache per state dir / per resolved config (e.g. key on plugin name + state dir hash), so a headless run against the unconfigured default dir cannot poison isolated bot state dirs.
- Surface a warning in
--channelssessions when the poller is not spawned due to a needs-auth cache hit (and ideally re-validate auth against the actual resolved state dir instead of trusting the cache).
Either one alone would have prevented or immediately revealed this failure; both together would be ideal.
Related (searched, not duplicates)
- #80635 — needs-auth cache keyed by server name poisoned by
claude mcp listblocking a later--mcp-configrun. Same underlying "cache keyed too coarsely" defect, but different trigger (mcp list vs headless-p) and different victim (MCP tool availability vs the channels poller, which fails silently). - #78220 — stale needs-auth flag keyed by server name, not cleared by
mcp remove. - #76449 — plugin stdio MCP server silently classified "needs auth" with stderr discarded (Cowork).
This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗