Bug
In scripts/notification-relay.cjs:304-308, sendTelegram calls itself on HTTP 429 with no retry counter:
if (res.status === 429) {
const body = await res.json().catch(() => ({}));
const wait = ((body.parameters?.retry_after ?? 5) + 1) * 1000;
await new Promise(r => setTimeout(r, wait));
return sendTelegram(userId, chatId, text); // "single retry" — but no guard
}
The comment says "single retry" but there's no depth/counter parameter to enforce it. If Telegram keeps returning 429 (sustained rate limiting during alert bursts), this recurses indefinitely.
Impact
Under sustained Telegram rate limiting, the relay could hit a stack overflow and crash on Railway. In practice this is rare since retry_after usually resolves it, but it's not guaranteed.
Fix
Add a _retryCount parameter (default 0), pass _retryCount + 1 on recursion, bail if _retryCount >= 1.
Verification Steps
Ref: #2173
Bug
In
scripts/notification-relay.cjs:304-308,sendTelegramcalls itself on HTTP 429 with no retry counter:The comment says "single retry" but there's no depth/counter parameter to enforce it. If Telegram keeps returning 429 (sustained rate limiting during alert bursts), this recurses indefinitely.
Impact
Under sustained Telegram rate limiting, the relay could hit a stack overflow and crash on Railway. In practice this is rare since
retry_afterusually resolves it, but it's not guaranteed.Fix
Add a
_retryCountparameter (default 0), pass_retryCount + 1on recursion, bail if_retryCount >= 1.Verification Steps
sendTelegramsignature — confirm it has a_retryCountparameter defaulting to 0_retryCount + 1_retryCount >= 1Ref: #2173