Skip to content

Baileys RC9 Auth Breaking Changes — Device Pairing Patches #19907

Description

@ron-flytech

Submitted by: Ron at FlyTech

Summary

Baileys 7.0.0-rc.9 (bundled with OpenClaw) has three bugs in the authentication handshake that cause 100% connection failure. Every attempt fails with 401 Unauthorized - device_removed in a reconnect loop. This issue documents the root causes and provides the exact patches to fix them.

Environment

  • OpenClaw with bundled Baileys @whiskeysockets/baileys 7.0.0-rc.9
  • Compared against known-working Baileys 6.17.16

Symptoms

[INFO]  Connecting to WhatsApp...
[ERROR] Connection closed with reason: 401 Unauthorized - device_removed
[INFO]  Reconnecting... (1/10)
[ERROR] Connection closed with reason: 401 Unauthorized - device_removed

Infinite reconnect loop. No pairing code is ever generated. Affects both QR and phone-number pairing flows.


Patch 1: Passive Flag — validate-connection.js line 53

File: lib/Utils/validate-connection.js

The generateLoginNode function sends passive: true in the client payload. WhatsApp's server interprets this as a passive listener and immediately terminates the connection with device_removed. It must be false for active device connections.

 export const generateLoginNode = (userJid, config) => {
     const { user, device } = jidDecode(userJid);
     const payload = {
         ...getClientPayload(config),
-        passive: true,
+        passive: false,
         pull: true,
         username: +user,
         device: device,

Sed fix:

sudo sed -i 's/passive: true,/passive: false,/g' \
  "$BAILEYS/Utils/validate-connection.js"

Patch 2: Remove Unknown lidDbMigrated Field — validate-connection.js line 58

File: lib/Utils/validate-connection.js

RC9 added lidDbMigrated: false to the login payload. This field doesn't exist in WhatsApp's protocol spec — the server rejects payloads containing it. The source even has a // TODO: investigate comment, suggesting it was experimental.

         username: +user,
         device: device,
         // TODO: investigate (hard set as false atm)
-        lidDbMigrated: false
     };
     return proto.ClientPayload.fromObject(payload);
 };

Sed fix:

sudo sed -i '/lidDbMigrated: false/d' \
  "$BAILEYS/Utils/validate-connection.js"

Patch 3: Noise Protocol Timing — socket.js line 324

File: lib/Socket/socket.js

RC9 incorrectly awaits noise.finishInit() after sending the client finish frame. This creates a race condition: the keep-alive request fires before the noise handshake state is fully committed. Removing the await matches the working 6.17.16 behavior.

             }
         }).finish());
-        await noise.finishInit();
+        noise.finishInit();
         startKeepAliveRequest();
     };

Sed fix:

sudo sed -i 's/await noise\.finishInit();/noise.finishInit();/g' \
  "$BAILEYS/Socket/socket.js"

Complete Fix Script

#!/bin/bash
# baileys-rc9-fix.sh — Fixes auth in Baileys 7.0.0-rc.9 bundled with OpenClaw
set -e

BAILEYS="/usr/lib/node_modules/openclaw/node_modules/@whiskeysockets/baileys/lib"

if [ ! -d "$BAILEYS" ]; then
    echo "❌ Baileys not found at $BAILEYS — update the path for your installation"
    exit 1
fi

echo "📦 Creating backups..."
sudo cp "$BAILEYS/Utils/validate-connection.js" "$BAILEYS/Utils/validate-connection.js.orig"
sudo cp "$BAILEYS/Socket/socket.js" "$BAILEYS/Socket/socket.js.orig"

echo "🔨 Patch 1: passive: true → false"
sudo sed -i 's/passive: true,/passive: false,/g' "$BAILEYS/Utils/validate-connection.js"

echo "🔨 Patch 2: removing lidDbMigrated field"
sudo sed -i '/lidDbMigrated: false/d' "$BAILEYS/Utils/validate-connection.js"

echo "🔨 Patch 3: noise.finishInit() timing"
sudo sed -i 's/await noise\.finishInit();/noise.finishInit();/g' "$BAILEYS/Socket/socket.js"

echo "✅ All patches applied. Restart your OpenClaw gateway to take effect."
echo "💾 Originals saved with .orig extension"

Verification

After patching, confirm with:

# Patch 1
grep 'passive:' "$BAILEYS/Utils/validate-connection.js"
# Should show: passive: false,

# Patch 2
grep 'lidDbMigrated' "$BAILEYS/Utils/validate-connection.js"
# Should return nothing

# Patch 3
grep 'noise.finishInit' "$BAILEYS/Socket/socket.js"
# Should show: noise.finishInit();  (no await)

Phone Number Pairing

With patches applied, phone-number pairing works. Key requirements:

  • Browser string must be exactly ['Mac OS', 'Chrome', '14.4.1']
  • defaultQueryTimeoutMs: undefined during pairing to prevent premature timeout
  • useMultiFileAuthState() for session persistence across restarts
  • On badSession disconnect, clear auth directory and retry
const sock = makeWASocket({
    auth: state,
    browser: ['Mac OS', 'Chrome', '14.4.1'],
    printQRInTerminal: false,
    defaultQueryTimeoutMs: undefined,
});

// Request pairing code when QR is available
sock.ev.on('connection.update', async ({ qr, connection }) => {
    if (qr) {
        const code = await sock.requestPairingCode(phoneNumber);
        console.log(`Enter this code in WhatsApp > Linked Devices: ${code}`);
    }
    if (connection === 'open') {
        console.log('✅ Connected!');
    }
});

sock.ev.on('creds.update', saveCreds);

Suggested Action

Consider either:

  1. Pinning OpenClaw's bundled Baileys to a known-working version (e.g., 6.17.16)
  2. Applying these three patches to the RC9 bundle in the OpenClaw distribution

These are surgical fixes — they only correct the three specific auth regressions without side effects.

Metadata

Metadata

Assignees

No one assigned

    Labels

    staleMarked as stale due to inactivity

    Type

    No type

    Fields

    Priority

    None yet

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions