-
-
Notifications
You must be signed in to change notification settings - Fork 57.5k
Description
Bug Summary
The LINE channel enters an infinite crash loop immediately after starting. The monitorLineProvider() async function resolves instantly after registering the webhook HTTP handler, causing the channel manager to interpret this as "channel exited" and trigger restart logic.
Reproduction
- Configure a LINE channel in
openclaw.jsonwith valid credentials - Enable the channel (
enabled: true) - Observe gateway logs:
[line] [default] starting LINE provider (Cattia)
[line] [default] auto-restart attempt 1/10 in 5s
[line] [default] starting LINE provider (Cattia)
[line] [default] auto-restart attempt 2/10 in 10s
...
[line] [default] giving up after 10 restart attempts
[health-monitor] [line:default] health-monitor: restarting (reason: gave-up)
The cycle repeats indefinitely: 10 exponential-backoff restart attempts → give up → health monitor restarts → repeat.
Root Cause
In extensions/line/src/channel.ts line 654, startAccount returns the result of monitorLineProvider():
// extensions/line/src/channel.ts:654
return getLineRuntime().channel.line.monitorLineProvider({...});monitorLineProvider() (in src/line/monitor.ts) registers the webhook HTTP handler and immediately returns { account, handleWebhook, stop }. It does NOT block on the abortSignal.
The channel manager in gateway-cli (line ~2330) expects startAccount to return a long-running promise that only resolves when the channel is stopped. When it resolves immediately, .finally() sets running: false and .then() triggers auto-restart.
Comparison with Telegram
Telegram's monitorTelegramProvider() correctly blocks on the abort signal in webhook mode (compiled bundle line ~61170):
// After registering webhook handler:
if (abortSignal && !abortSignal.aborted) await new Promise((resolve) => {
const onAbort = () => {
abortSignal.removeEventListener("abort", onAbort);
resolve();
};
abortSignal.addEventListener("abort", onAbort, { once: true });
});LINE's monitorLineProvider() is missing this pattern entirely.
Fix
Add the abort-signal blocking pattern to monitorLineProvider() in src/line/monitor.ts, after the abortSignal?.addEventListener("abort", stopHandler) line and before the return statement:
abortSignal?.addEventListener("abort", stopHandler);
// Add this block to keep the promise alive until abort
if (abortSignal && !abortSignal.aborted) {
await new Promise<void>((resolve) => {
const onAbort = () => {
abortSignal.removeEventListener("abort", onAbort);
resolve();
};
abortSignal.addEventListener("abort", onAbort, { once: true });
});
}
return { account: bot.account, handleWebhook: bot.handleWebhook, stop: ... };Impact
- LINE channel is completely unusable without this fix
- The crash loop consumes gateway resources (timers, log spam)
- Health monitor's 3-restarts/hour limit is exhausted by LINE, potentially delaying recovery of other channels
Environment
- OpenClaw version: 2026.2.24
- Platform: macOS (darwin arm64)
- Node.js: 22.22.0
Workaround
Manually patch monitorLineProvider() in the compiled dist bundles:
dist/subagent-registry-*.jsdist/pi-embedded-*.jsdist/reply-*.js
Note: patches are overwritten on npm update.