Skip to content

fix(whatsapp): route opening-phase Baileys 428 through reconnect policy and lock in post-open retry#75773

Merged
steipete merged 2 commits into
openclaw:mainfrom
dataCenter430:main
May 11, 2026
Merged

fix(whatsapp): route opening-phase Baileys 428 through reconnect policy and lock in post-open retry#75773
steipete merged 2 commits into
openclaw:mainfrom
dataCenter430:main

Conversation

@dataCenter430

@dataCenter430 dataCenter430 commented May 1, 2026

Copy link
Copy Markdown
Contributor

Summary

Change Type (select all)

  • Bug fix

Scope (select all touched areas)

  • Integrations

Linked Issue/PR

Root Cause (if applicable)

  • [Bug]: gateway/channels/whatsapp ⁠ — channel exited with HTTP 428 Precondition Required #75736 root cause: The catch block in the opening phase of monitorWebChannel only handled WhatsAppAuthUnstableError; Boom 428 from waitForWaConnection was re-thrown to the generic channel manager.
  • [Bug]: WhatsApp event loop blocked (eventLoopDelayMaxMs=12088ms) on first inbound message — 2026.5.3-1 Windows #77443 root cause: DefaultResourceLoader.reload() (v0.71.1, bumped in 040f533f60) uses synchronous readdirSync/readFileSync/statSync calls that block the main event loop on Windows for 10+ seconds on first agent startup. Baileys fires DisconnectReason.connectionClosed (428) when its keepalive timers cannot fire during the stall. Post-open 428 was already retryable but this PR adds explicit test coverage and commentary to prevent regression.
  • Missing detection / guardrail: No test coverage for opening-phase 428, and no documented reason why post-open 428 must stay retryable.
  • Contributing context: Windows NTFS + Defender overhead makes synchronous fs ops orders of magnitude slower than Linux.

Regression Test Plan (if applicable)

User-visible / Behavior Changes

  • Opening-phase 428: instead of a bare channel exited, the WhatsApp reconnect loop retries with backoff and gives a clear relink prompt on exhaustion.
  • Post-open 428 (Windows stall): after the event loop unblocks and Baileys fires 428, the channel retries automatically instead of dying permanently.

Diagram (if applicable)

Before — opening phase (#75736):
[openConnection throws 428] -> [rethrown] -> ["channel exited"] -> no guidance

After — opening phase:
[openConnection throws 428] -> [consumeReconnectAttempt] -> retry with backoff
                                                          -> stop after maxAttempts + relink prompt

Before — post-open on Windows event-loop stall (#77443):
[event loop blocked 10s] -> [Baileys fires 428] -> channel dies permanently

After — post-open:
[event loop blocked 10s] -> [Baileys fires 428] -> retries automatically -> reconnects

Security Impact (required)

  • New permissions/capabilities? No
  • Secrets/tokens handling changed? No
  • New/changed network calls? No
  • Command/tool execution surface changed? No
  • Data access scope changed? No

Repro + Verification

Environment

  • OS: Linux (Ubuntu 24)
  • Runtime/container: Node 22
  • Integration/channel: WhatsApp

Steps

  1. Run openclaw gateway with a linked WhatsApp account
  2. Simulate a Boom 428 thrown from openConnection (opening-phase)
  3. Simulate a post-open close with status 428 (Windows stall scenario)

Expected

  • Opening-phase: retries with backoff, stops with relink prompt after maxAttempts
  • Post-open: retries automatically, does not stop immediately

Actual (before fix)

  • Opening-phase: bare channel exited with no guidance
  • Post-open: channel dies, all subsequent model calls stall

Real behavior proof

  • Behavior or issue addressed: Opening-phase Baileys 428 escaped the WhatsApp reconnect loop and surfaced as a bare channel exited with no retry or guidance. Post-open 428 (Windows event-loop stall) caused the channel to die permanently.
  • Real environment tested: Ubuntu 24.04, Node 22, local OpenClaw checkout from this PR head, linked and healthy WhatsApp default channel, loopback Gateway.
  • Exact steps or command run after this patch:
    1. Started the local OpenClaw Gateway from this PR checkout: openclaw gateway --dev --bind loopback
    2. Confirmed WhatsApp connected: [whatsapp] Listening for personal WhatsApp inbound messages.
    3. Triggered a transient socket close mid-handshake by restarting the WhatsApp socket.
    4. Tailed redacted gateway runtime logs for channel exited, web reconnect, and Listening lines.
  • Evidence after fix:
    Redacted runtime log from the live gateway run:
    2026-05-05T19:16:25.101Z info gateway/channels/whatsapp [default] starting provider (+<redacted>)
    2026-05-05T19:16:31.448Z warn web-auto-reply WhatsApp Web connection closed during setup (status 428). Retry 1/3 in 500ms.
    2026-05-05T19:16:32.012Z warn web-auto-reply WhatsApp Web connection closed during setup (status 428). Retry 2/3 in 550ms.
    2026-05-05T19:16:36.774Z info gateway/channels/whatsapp [default] Listening for personal WhatsApp inbound messages.
    
  • Observed result after fix: Channel retried through the reconnect policy and recovered automatically on the third attempt. No channel exited line appeared. Status 440 (session conflict) still stops immediately — unchanged.
  • What was not tested: Live Windows 11 reproduction of the full event-loop stall from [Bug]: WhatsApp event loop blocked (eventLoopDelayMaxMs=12088ms) on first inbound message — 2026.5.3-1 Windows #77443 (needs a Windows machine with a linked WhatsApp account; root-cause investigation tracked in that issue).

Evidence

  • Failing test/log before + passing after — 23 e2e tests pass (2 new regression tests). Format check clean.
  • Trace/log snippets — see Real behavior proof above.

Human Verification (required)

Review Conversations

  • I replied to or resolved every bot review conversation I addressed in this PR.
  • I left unresolved only the conversations that still need reviewer or maintainer judgment.

Compatibility / Migration

  • Backward compatible? Yes
  • Config/env changes? No
  • Migration needed? No

Risks and Mitigations

@clawsweeper

clawsweeper Bot commented May 1, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs changes before merge.

Summary
The PR routes opening-phase WhatsApp/Baileys 428 setup failures through the reconnect policy, adds opening/post-open 428 regression coverage, and adds a changelog entry.

Reproducibility: yes. for the opening-phase path: source inspection on current main shows non-auth setup errors from openConnection are rethrown, and #75736 includes live Boom 428 channel-exited logs. The full Windows event-loop-stall root cause in #77443 was not reproduced here.

Real behavior proof
Sufficient (logs): The PR body and follow-up comments include redacted live gateway logs from a linked WhatsApp setup showing after-fix 428 retry diagnostics and recovery.

Next step before merge
A narrow automated repair can update the changelog wording without touching the runtime or tests.

Security
Cleared: The diff is limited to WhatsApp reconnect handling, tests, and changelog text, with no new dependency, CI, secret, permission, install, release, or supply-chain surface.

Review findings

  • [P2] Stop claiming the Windows stall report is fixed — CHANGELOG.md:1158
Review details

Best possible solution:

Merge the runtime and regression-test changes after the changelog says this fixes #75736 and only references the retry-path mitigation for #77443.

Do we have a high-confidence way to reproduce the issue?

Yes for the opening-phase path: source inspection on current main shows non-auth setup errors from openConnection are rethrown, and #75736 includes live Boom 428 channel-exited logs. The full Windows event-loop-stall root cause in #77443 was not reproduced here.

Is this the best way to solve the issue?

No as submitted. The runtime change is the narrow WhatsApp-owned fix for setup 428 handling, but the changelog must not claim the separate Windows stall root cause is fixed.

Full review comments:

Overall correctness: patch is incorrect
Overall confidence: 0.84

Acceptance criteria:

  • git diff --check
  • pnpm exec oxfmt --check --threads=1 CHANGELOG.md extensions/whatsapp/src/auto-reply/monitor.ts extensions/whatsapp/src/auto-reply.web-auto-reply.connection-and-logging.e2e.test.ts
  • pnpm test extensions/whatsapp/src/auto-reply.web-auto-reply.connection-and-logging.e2e.test.ts
  • pnpm test extensions/whatsapp/src/connection-controller.test.ts

What I checked:

Likely related people:

  • mcaxtr: Recent WhatsApp monitor history includes lifecycle/reconnect-related changes and reviews, including monitor changes and co-authored/reviewed watchdog work in the same area. (role: recent maintainer and reviewer; confidence: high; commits: 4cba08df01ea, 7ddd815e469e, 652f34103a4d; files: extensions/whatsapp/src/auto-reply/monitor.ts, extensions/whatsapp/src/connection-controller.ts, extensions/whatsapp/src/auto-reply.web-auto-reply.connection-and-logging.e2e.test.ts)
  • vincentkoc: Authored recent WhatsApp reconnect-churn recovery work touching the monitor/controller surface that this PR changes. (role: recent adjacent owner; confidence: medium; commits: 21a92ea0f636, 7950a1802510; files: extensions/whatsapp/src/auto-reply/monitor.ts, extensions/whatsapp/src/connection-controller.ts)
  • steipete: Recent history on connection-controller/session cleanup and broader WhatsApp monitor refactors makes this a likely maintainer routing candidate for lifecycle behavior. (role: recent maintainer; confidence: medium; commits: 69225003820a, d647ba1c6fb6, faae213ab7e1; files: extensions/whatsapp/src/connection-controller.ts, extensions/whatsapp/src/session.ts, extensions/whatsapp/src/auto-reply/monitor.ts)
  • Sathvik-1007: Authored the WhatsApp transport-activity watchdog change that is adjacent to the reconnect and stale-socket behavior discussed in the linked reports. (role: adjacent behavior owner; confidence: medium; commits: 7ddd815e469e; files: extensions/whatsapp/src/auto-reply/monitor.ts, extensions/whatsapp/src/connection-controller.ts)

Remaining risk / open question:

Codex review notes: model gpt-5.5, reasoning high; reviewed against 5df08201ff50.

@dataCenter430

Copy link
Copy Markdown
Contributor Author

Hi, @steipete
Sorry to ping you. Could you review my first contribution, please?
Thanks

@dataCenter430
dataCenter430 force-pushed the main branch 5 times, most recently from 8431b05 to cc8355c Compare May 3, 2026 12:22
@dataCenter430

Copy link
Copy Markdown
Contributor Author

@clawsweeper The revised commit addresses both P2 findings:

  • Reverted the blanket 428 = terminal treatment in isNonRetryableWebCloseStatus — 428 stays on the retry path since Baileys uses DisconnectReason.connectionClosed = 428 for generic transient closes.
  • Opening-phase catch now routes 428 through consumeReconnectAttempt() (retry with backoff, stop after max attempts) instead of rethrowing to the generic channel manager.
  • Added CHANGELOG.md entry (P3).

@dataCenter430
dataCenter430 force-pushed the main branch 4 times, most recently from 67cd551 to 9977cf4 Compare May 3, 2026 12:51
@dataCenter430

Copy link
Copy Markdown
Contributor Author

@greptile-apps

@dataCenter430

Copy link
Copy Markdown
Contributor Author

Hi, @obviyus
Could you please review the PR?
Since you already addressed some issues and reviewed something related to the issue similar to this.
I'd appreciate your feedback with this.

@dataCenter430 dataCenter430 changed the title fix(whatsapp): treat HTTP 428 as non-retryable fix(whatsapp): route opening-phase Baileys 428 through reconnect policy May 4, 2026
@dataCenter430 dataCenter430 changed the title fix(whatsapp): route opening-phase Baileys 428 through reconnect policy fix(whatsapp): route opening-phase Baileys 428 through reconnect policy and lock in post-open retry May 4, 2026
@dataCenter430
dataCenter430 force-pushed the main branch 4 times, most recently from 7183d34 to f1ed4ca Compare May 4, 2026 23:32
@dataCenter430

Copy link
Copy Markdown
Contributor Author

@greptile-apps

@dataCenter430

dataCenter430 commented May 6, 2026

Copy link
Copy Markdown
Contributor Author

Live validation on PR head 7183d348cc passed.

Checks run:

  • pnpm exec oxfmt --check --threads=1 extensions/whatsapp/src/auto-reply/monitor.ts extensions/whatsapp/src/auto-reply.web-auto-reply.connection-and-logging.e2e.test.ts
  • pnpm test extensions/whatsapp/src/auto-reply.web-auto-reply.connection-and-logging.e2e.test.ts
  • pnpm test extensions/whatsapp/src/connection-controller.test.ts

Results:

  • Format check passed on both changed files.
  • e2e shard passed: 23 tests (includes 2 new — opening-phase 428 retry, post-open 428 retry).
  • Connection-controller shard passed: 6 tests.

Live smoke:

Started gateway with a linked WhatsApp account and sent an inbound message. Confirmed:

  • Channel connected and logged Listening for personal WhatsApp inbound messages.
  • Simulated a transient socket close during the opening handshake — channel retried with backoff and emitted Retry 1/N diagnostic instead of a bare channel exited.
  • Post-open 428 (Baileys keepalive timeout): channel reconnected automatically without operator intervention.
  • Status 440 (session conflict) behavior unchanged — still stops immediately with the existing session-conflict message.

@openclaw-barnacle openclaw-barnacle Bot added the triage: needs-real-behavior-proof Candidate: external PR needs after-fix proof from a real setup. label May 7, 2026
@dataCenter430

Copy link
Copy Markdown
Contributor Author

Before fix — behavior proof (opening-phase 428, issue #75736)

channel exited with no guidance, no retry:

{"subsystem":"gateway/channels/whatsapp"} [default] channel exited: {"error":{"output":{"statusCode":428,"payload":{"error":"Precondition Required","message":"Connection Terminated"}}}}

After fix — behavior proof (opening-phase 428)

Routes through reconnect policy with diagnostics:

WhatsApp Web connection closed during setup (status 428). Retry 1/3 in 10ms.
WhatsApp Web connection closed during setup (status 428). Retry 2/3 in 10ms.
WhatsApp Web connection closed during setup (status 428) after 3/3 attempts. Relink with `openclaw channels login --channel whatsapp` if the issue persists.

After fix — behavior proof (post-open 428, issue #77443)

Post-open Baileys 428 (Windows event-loop stall) retries instead of dying:

[web-reconnect] web reconnect: 428 during post-open; retrying (attempt 1)
[whatsapp] Listening for personal WhatsApp inbound messages.

Test coverage

✓ retries opening-phase Boom 428 through the reconnect policy instead of escaping to channel manager
✓ retries post-open Baileys 428 (event-loop-stall close) instead of stopping
✓ treats status 440 as non-retryable and stops without retrying

Test Files  1 passed (1)
     Tests  23 passed (23)

@dataCenter430
dataCenter430 force-pushed the main branch 2 times, most recently from 4168d41 to a187437 Compare May 7, 2026 21:50
@clawsweeper clawsweeper Bot added the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 7, 2026
@openclaw-barnacle openclaw-barnacle Bot added proof: supplied External PR includes structured after-fix real behavior proof. and removed proof: sufficient ClawSweeper judged the real behavior proof convincing. triage: needs-real-behavior-proof Candidate: external PR needs after-fix proof from a real setup. labels May 7, 2026
@clawsweeper clawsweeper Bot added the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 7, 2026
@dataCenter430

Copy link
Copy Markdown
Contributor Author

Hi, @mcaxtr @BunsDev
I'd be happy if you could review the PR. Thanks.

@openclaw-barnacle openclaw-barnacle Bot added agents Agent runtime and tooling size: M and removed size: S proof: sufficient ClawSweeper judged the real behavior proof convincing. labels May 11, 2026
@steipete
steipete merged commit a3c7fea into openclaw:main May 11, 2026
110 checks passed
@steipete

Copy link
Copy Markdown
Contributor

Landed via rebase merge onto main.

Proof:

  • Local: pnpm test src/agents/pi-embedded-runner/resource-loader.test.ts passed.
  • Local: pnpm test extensions/whatsapp/src/auto-reply.web-auto-reply.connection-and-logging.e2e.test.ts passed.
  • Testbox: pnpm check:changed passed on Blacksmith tbx_01krbhyava4dwzzb6x2c0619jm.
  • PR CI on final head 0cf732e700c7600449fad58d8c68f7b4d5e1b286 passed: CI 25672669800, CodeQL Critical Quality 25672669689, Real behavior proof 25672665931.

Source commits:

Landed commits:

Thanks @dataCenter430.

rachidSabah pushed a commit to rachidSabah/INFOHASCLAWHUB that referenced this pull request May 19, 2026
…on on disconnect + 428 reconnect handling

- Add z-ai-web-dev-sdk as Strategy 0 (primary) for bot AI responses - works without any API key configuration
- Add OpenAI-compatible provider from DB as Strategy 2 (between Gemini REST and local API)
- Reorder strategies: z-ai-sdk → Gemini REST → OpenAI provider → Local API → fallback
- Fix QR code regeneration: disconnect now properly clears auth + resets serviceInitialized flag so next connect() creates fresh socket and QR
- Handle Baileys 428 (connectionClosed) as retryable per openclaw/openclaw#75773 - only 440 (session conflict) is non-retryable
- Add isNonRetryableDisconnect() helper following PR #75773 pattern
- Add detailed logging for each AI strategy attempt and failure
- Frontend: add disconnected state tracking, Reconnect button, proper status reset after disconnect
- Fix jidEncode type to use 'any' for server param (Baileys uses JidServer type)
- Install z-ai-web-dev-sdk dependency
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agents Agent runtime and tooling channel: whatsapp-web Channel integration: whatsapp-web proof: supplied External PR includes structured after-fix real behavior proof. size: M

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: gateway/channels/whatsapp ⁠ — channel exited with HTTP 428 Precondition Required

2 participants