openclaw - ✅(Solved) Fix startWebLoginWithCode calls requestPairingCode before socket reaches connecting state [1 pull requests, 1 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
openclaw/openclaw#56797Fetched 2026-04-08 01:47:40
View on GitHub
Comments
0
Participants
1
Timeline
2
Reactions
0
Author
Participants
Timeline (top)
cross-referenced ×2

PR fix notes

PR #59210: docs(whatsapp): clarify remote QR pairing limitations

Description (problem / solution / changelog)

Summary

Document the practical limitations of the current QR-only WhatsApp login flow in remote/headless setups.

Why

We hit a real-world failure mode where:

  • OpenClaw WhatsApp login was QR-only
  • the target machine was not physically nearby
  • relaying the QR through screenshots / PDFs / chat attachments was brittle
  • the QR refreshed or expired underneath the handoff

This does not add new behavior. It makes the limitation explicit in the channel docs and nudges users toward a direct QR image handoff plan instead of assuming terminal capture will be fine.

Notes

  • This PR does not claim phone-number / pairing-code login is available in the current documented flow.
  • Related issues:
    • #45652
    • #56797

Changed files

  • docs/channels/whatsapp.md (modified, +21/-0)

Code Example

sock.ev.on('connection.update', async (update) => {
  const {connection, lastDisconnect, qr} = update
  if (connection == "connecting" || !!qr) {
    const code = await sock.requestPairingCode(phoneNumber)
  }
})

---

// login-qr.ts — startWebLoginWithCode
sock = await createWaSocket(false, Boolean(opts.verbose), { authDir: account.authDir });
// ... immediately:
const code = await sock.requestPairingCode(digits); // fails — socket not ready

---

sock = await createWaSocket(false, Boolean(opts.verbose), {
  authDir: account.authDir,
  onQr: () => { /* socket is now in connecting state */ },
});
// Wait for onQr to fire
const code = await sock.requestPairingCode(digits); // now works
RAW_BUFFERClick to expand / collapse

Bug

startWebLoginWithCode() in extensions/whatsapp/src/login-qr.ts calls sock.requestPairingCode(digits) immediately after createWaSocket() returns, without waiting for the socket to reach the "connecting" state. This causes requestPairingCode to fail with "Connection Closed" every time.

Expected behavior

Per the Baileys docs, requestPairingCode must only be called after the socket emits a connection.update with connection === "connecting" or a QR event:

sock.ev.on('connection.update', async (update) => {
  const {connection, lastDisconnect, qr} = update
  if (connection == "connecting" || !!qr) {
    const code = await sock.requestPairingCode(phoneNumber)
  }
})

Current code (broken)

// login-qr.ts — startWebLoginWithCode
sock = await createWaSocket(false, Boolean(opts.verbose), { authDir: account.authDir });
// ... immediately:
const code = await sock.requestPairingCode(digits); // fails — socket not ready

Suggested fix

Wait for the QR/connecting event before calling requestPairingCode:

sock = await createWaSocket(false, Boolean(opts.verbose), {
  authDir: account.authDir,
  onQr: () => { /* socket is now in connecting state */ },
});
// Wait for onQr to fire
const code = await sock.requestPairingCode(digits); // now works

Compare with startWebLoginWithQr which correctly waits for the QR event before proceeding.

Environment

extent analysis

Fix Plan

To fix the issue, we need to wait for the socket to reach the "connecting" state before calling requestPairingCode.

Here are the steps:

  • Create a promise that resolves when the socket emits a connection.update with connection === "connecting" or a QR event.
  • Wait for this promise to resolve before calling requestPairingCode.

Example Code

// login-qr.ts — startWebLoginWithCode
sock = await createWaSocket(false, Boolean(opts.verbose), { authDir: account.authDir });

// Create a promise that resolves when the socket is ready
const socketReady = new Promise((resolve) => {
  sock.ev.on('connection.update', async (update) => {
    const { connection, lastDisconnect, qr } = update;
    if (connection === "connecting" || !!qr) {
      resolve();
    }
  });
});

// Wait for the socket to be ready
await socketReady;

// Now it's safe to call requestPairingCode
const code = await sock.requestPairingCode(digits);

Verification

To verify that the fix worked, you can test the startWebLoginWithCode function and check that requestPairingCode is called successfully without throwing a "Connection Closed" error.

Extra Tips

Make sure to handle any potential errors that may occur while waiting for the socket to be ready. You can do this by adding a timeout to the socketReady promise or by catching any errors that may be thrown.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

FAQ

Expected behavior

Per the Baileys docs, requestPairingCode must only be called after the socket emits a connection.update with connection === "connecting" or a QR event:

sock.ev.on('connection.update', async (update) => {
  const {connection, lastDisconnect, qr} = update
  if (connection == "connecting" || !!qr) {
    const code = await sock.requestPairingCode(phoneNumber)
  }
})

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING