fix(discord): suppress intentional reconnect exception during health monitor restart#55042
fix(discord): suppress intentional reconnect exception during health monitor restart#55042Bartok9 wants to merge 2 commits into
Conversation
…monitor restart When the Discord health monitor triggers a restart (e.g., due to stale-socket detection), the onAbort handler sets maxAttempts to 0 before calling disconnect(). The gateway library interprets this as a reconnection failure and throws 'Max reconnect attempts (0) reached' — causing an uncaught exception that crashes the entire gateway process. This fix wraps the disconnect() call in a try-catch that specifically suppresses the expected 'Max reconnect attempts' error during intentional aborts, while still rethrowing any other unexpected errors. Fixes openclaw#55026
Greptile SummaryThis PR fixes a recurring gateway process crash (~every 30 minutes) caused by the health monitor's Confidence Score: 5/5Safe to merge — the fix correctly suppresses an intentional exception without masking real errors, and both new test cases pass. The change is small, targeted, and well-tested. The root cause (gateway library throwing on maxAttempts: 0) is clearly documented and the suppression logic is tight. The only open item is a P2 style suggestion about using err.message vs String(err), which does not affect correctness. No files require special attention.
|
| Filename | Overview |
|---|---|
| extensions/discord/src/monitor/provider.lifecycle.ts | Wraps gateway.disconnect() in onAbort with a targeted try-catch that suppresses the expected 'Max reconnect attempts (0) reached' exception while rethrowing anything else. The logic is correct and well-scoped. |
| extensions/discord/src/monitor/provider.lifecycle.test.ts | Adds two well-structured tests covering both the suppression path and the rethrow path. Uses the pre-aborted signal pattern to exercise onAbort() synchronously, which is appropriate for these scenarios. |
Prompt To Fix All With AI
This is a comment left during a code review.
Path: extensions/discord/src/monitor/provider.lifecycle.ts
Line: 139-142
Comment:
**Fragile string-match for error detection**
The suppression logic relies on a partial string match against the serialised error. Two minor concerns:
1. `String(err)` on an `Error` instance yields `"Error: Max reconnect attempts …"`, so the match works today — but using `err instanceof Error ? err.message : String(err)` makes the intent clearer and avoids accidentally matching a hypothetical `Error: Something wrapping 'Max reconnect attempts'` object.
2. If the upstream gateway library ever changes its error message wording, the condition silently stops suppressing, and the crash resurfaces with no warning. Centralising the sentinel string in a named constant (e.g. `const MAX_RECONNECT_ERROR_PREFIX = "Max reconnect attempts"`) makes future auditing easier.
```suggestion
const message = err instanceof Error ? err.message : String(err);
if (!message.includes("Max reconnect attempts")) {
throw err;
}
```
How can I resolve this? If you propose a fix, please make it concise.Reviews (1): Last reviewed commit: "fix(discord): suppress intentional recon..." | Re-trigger Greptile
| const message = String(err); | ||
| if (!message.includes("Max reconnect attempts")) { | ||
| throw err; | ||
| } |
There was a problem hiding this comment.
Fragile string-match for error detection
The suppression logic relies on a partial string match against the serialised error. Two minor concerns:
-
String(err)on anErrorinstance yields"Error: Max reconnect attempts …", so the match works today — but usingerr instanceof Error ? err.message : String(err)makes the intent clearer and avoids accidentally matching a hypotheticalError: Something wrapping 'Max reconnect attempts'object. -
If the upstream gateway library ever changes its error message wording, the condition silently stops suppressing, and the crash resurfaces with no warning. Centralising the sentinel string in a named constant (e.g.
const MAX_RECONNECT_ERROR_PREFIX = "Max reconnect attempts") makes future auditing easier.
| const message = String(err); | |
| if (!message.includes("Max reconnect attempts")) { | |
| throw err; | |
| } | |
| const message = err instanceof Error ? err.message : String(err); | |
| if (!message.includes("Max reconnect attempts")) { | |
| throw err; | |
| } |
Prompt To Fix With AI
This is a comment left during a code review.
Path: extensions/discord/src/monitor/provider.lifecycle.ts
Line: 139-142
Comment:
**Fragile string-match for error detection**
The suppression logic relies on a partial string match against the serialised error. Two minor concerns:
1. `String(err)` on an `Error` instance yields `"Error: Max reconnect attempts …"`, so the match works today — but using `err instanceof Error ? err.message : String(err)` makes the intent clearer and avoids accidentally matching a hypothetical `Error: Something wrapping 'Max reconnect attempts'` object.
2. If the upstream gateway library ever changes its error message wording, the condition silently stops suppressing, and the crash resurfaces with no warning. Centralising the sentinel string in a named constant (e.g. `const MAX_RECONNECT_ERROR_PREFIX = "Max reconnect attempts"`) makes future auditing easier.
```suggestion
const message = err instanceof Error ? err.message : String(err);
if (!message.includes("Max reconnect attempts")) {
throw err;
}
```
How can I resolve this? If you propose a fix, please make it concise.Addresses review feedback: uses err.message when available instead of String(err) to avoid the 'Error: ' prefix in the serialized form. The matching behavior is unchanged since we use .includes().
|
Addressed the style feedback — now using |
|
This fix is needed — the stale-socket health monitor crash is hitting production users on 2026.3.24. The fix looks correct (try-catch around disconnect() to suppress the expected Max reconnect attempts error on intentional aborts). Happy to help test. Is there anything blocking merge? |
|
Closing this as implemented after Codex review. Current What I checked:
So I’m closing this as already implemented rather than keeping a duplicate issue open. Review notes: reviewed against 34896839ba22; fix evidence: commit 6a61cb73c562. |
Summary
When the Discord health monitor triggers a restart (e.g., due to stale-socket detection), the
onAborthandler setsmaxAttemptsto 0 before callingdisconnect(). The gateway library interprets this as a reconnection failure and throws "Max reconnect attempts (0) reached" — causing an uncaught exception that crashes the entire gateway process.Root Cause
The gateway library's disconnect flow treats
maxAttempts: 0as a signal that reconnection exhausted its attempts, throwing an error. However, in the health monitor's abort flow,maxAttempts: 0is intentionally set to prevent reconnection during a clean shutdown — this exception should not bubble up.Fix
Wrap the
gateway.disconnect()call in a try-catch that:Testing
Added two test cases:
suppresses 'Max reconnect attempts' exception during intentional abort— verifies the fixrethrows non-reconnect exceptions during abort— ensures we don't suppress legitimate errorsAll 17 tests in
provider.lifecycle.test.tspass.Impact
Fixes #55026