#23134: fix(gateway): skip auto-restart for webhook channels that resolve immediately
gateway
size: XS
Cluster:
Webhook Configuration and Resilience
## Summary
- Fix infinite auto-restart loop for webhook-based channels (Google Chat, BlueBubbles) introduced in v2026.2.17
- Track whether the channel task promise rejected and only auto-restart on error exit
- Channels that resolve cleanly (webhook route registered successfully) are not restarted
## Problem
The channel auto-restart hardening in v2026.2.17 wraps channel task promises with `.then(autoRestart)`. This fires when the promise **resolves**, not just when it rejects.
**Polling channels** (Telegram, Discord, Slack) return long-lived promises that stay pending — their event loop runs forever. The `.then()` only fires when they crash.
**Webhook channels** (Google Chat, BlueBubbles) register an HTTP route on the shared gateway server and resolve immediately — there is no long-running loop. The `.then()` fires right after startup, triggering an infinite restart cycle:
```
[googlechat] [fretron] starting Google Chat webhook
[googlechat] [fretron] auto-restart attempt 1/10 in 5s
[googlechat] [fretron] starting Google Chat webhook
[googlechat] [fretron] auto-restart attempt 2/10 in 10s
...
```
## Fix
Add a `didError` flag set in the `.catch()` handler. The `.then()` auto-restart handler checks this flag and returns early if the channel exited cleanly (no error). This preserves crash-loop recovery for polling channels while preventing spurious restarts for webhook channels.
## Bisect
| Version | Status |
|---------|--------|
| 2026.2.14 | OK |
| 2026.2.15 | OK (last good) |
| **2026.2.17** | **BROKEN** (first bad) |
| 2026.2.19+ | BROKEN |
## Test plan
- [x] Updated crash-loop test to use a throwing `startAccount` (simulates actual crash)
- [x] Updated manual-stop test to use a throwing `startAccount`
- [x] Added new test: webhook channel that resolves immediately is NOT restarted
- [ ] Existing tests pass (`vitest run src/gateway/server-channels.test.ts`)
Fixes #23114
🤖 Generated with [Claude Code](https://claude.com/claude-code)
<!-- greptile_comment -->
<h3>Greptile Summary</h3>
Fixes infinite restart loop for webhook-based channels (specifically Google Chat) by tracking whether the channel task promise rejected before attempting auto-restart. The fix adds a `didError` flag that is set in the `.catch()` handler, and the `.then()` auto-restart handler checks this flag to skip restarting channels that exited cleanly. This preserves crash-loop recovery for long-running polling channels while preventing spurious restarts for webhook channels that resolve immediately after registering their HTTP route.
<h3>Confidence Score: 5/5</h3>
- This PR is safe to merge with minimal risk
- The fix is simple, well-tested, and directly addresses the root cause. The logic correctly distinguishes between clean exits and error exits using a boolean flag. Test coverage includes the new webhook behavior plus updated tests for crash-loop scenarios. The only minor issue is an inaccurate example in a code comment.
- No files require special attention
<sub>Last reviewed commit: c547db1</sub>
<!-- 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
#20554: fix(googlechat): prevent infinite restart loop in startAccount
by Gitjay11 · 2026-02-19
84.2%
#20395: fix(googlechat): prevent infinite auto-restart and ambiguous-target...
by ggalmeida0 · 2026-02-18
82.9%
#23621: fix(LINE): keep startAccount promise alive to prevent auto-restart ...
by ttakanawa · 2026-02-22
79.1%
#23074: fix(synology-chat): prevent restart loop in startAccount
by druide67 · 2026-02-22
78.2%
#9727: fix(whatsapp): retry reconnect loop on initial connection failure
by luizlf · 2026-02-05
77.6%
#22322: fix(googlechat): keep webhook monitor alive until abort
by AIflow-Labs · 2026-02-21
76.6%
#17243: fix(telegram): catch getFile network failures to prevent gateway cr...
by robbyczgw-cla · 2026-02-15
76.3%
#21956: fix(line): block monitorLineProvider on abort signal to prevent cra...
by lailoo · 2026-02-20
75.8%
#21463: fix(discord): prevent WebSocket death spiral + fix numeric channel ID…
by akropp · 2026-02-20
75.5%
#22605: fix(msteams): keep provider promise pending until abort to stop aut...
by OpakAlex · 2026-02-21
75.4%