Baileys
LibraryWhiskeySockets/Baileys
Socket-based TypeScript library for interacting with WhatsApp Web API.
Overview
Baileys is a WebSockets-based TypeScript library for interacting with the WhatsApp Web API. It supports Node.js, Deno, and Bun, and is often used to build custom WhatsApp clients and automation tools. The project is not affiliated with WhatsApp and comes with an MIT license.
README Preview
\n\n\n> [!CAUTION]\n> NOTICE OF BREAKING CHANGE.\n>\n> As of 7.0.0, multiple breaking changes were introduced into the library.\n>\n> Please check out https://whiskey.so/migrate-latest for more information.\n\nBaileys is a WebSockets-based TypeScript library for interacting with the WhatsApp Web API.\n\nJoin the WhiskeySockets community via the link: https://whiskey.so/discord\n\n# Usage & Guide\n\n> [!IMPORTANT]\n> The new guide is a work in progress. Expect missing pages/content. [Report missing or incorrect content.](https://github.com/WhiskeySockets/baileys.wiki-site/issues/new)\n>\n> **You can still access the old guide here:** [README.md](https://github.com/WhiskeySockets/Baileys/tree/master/README.md), or the [NPM homepage](https://npmjs.com/package/baileys).\n\nThe new guide is posted at https://baileys.wiki .\n\n# Get Support\n\nIf you'd like business to enterprise-level support from Rajeh, the current maintainer of Baileys, you can book a video chat. Book a 1 hour time slot by contacting him on Discord or pre-ordering [here](https://purpshell.dev/book). The earlier you pre-order the better, as his time slots usually fill up very quickly. He offers immense value per hour and will answer all your questions before the time runs out.\n\nIf you are a business, we encourage you to contribute back to the high development costs of the project and to feed the maintainers who dump tens of hours a week on this. You can do so by booking meetings or sponsoring below. All support, even in bona fide / contribution hours, is welcome by businesses of all sizes. This is not condoning or endorsing businesses to use the library. See the Disclaimer below.\n\n# Sponsor\n\nIf you'd like to financially support this project, you can do so by supporting the current maintainer [here](https://purpshell.dev/sponsor).\n\n# Disclaimer\n> [!CAUTION]\n> This project is not affiliated, associated, authorized, endorsed by, or in any way officially connected with WhatsApp or any of its subsi
FAQ (5)
TroubleshootingHow to fix Baileys downloadMediaMessage hanging forever or crashing with 'TypeError: terminated' uncaughtException when a media download connection drops?
This is a bug in Baileys (confirmed in 7.0.0-rc13/rc14 and master): downloadEncryptedContent in src/Utils/messages-media.ts (line ~652) pipes the undici response stream without attaching an 'error' listener. When the connection is cut mid-body, undici raises TypeError: terminated on the source stream — since .pipe() does not forward errors, this becomes a process-level uncaughtException, and the destination stream is never ended, so await downloadMediaMessage(msg, 'buffer') never resolves or rejects and for await iteration hangs forever.
**Fix (patch the library):** In src/Utils/messages-media.ts, change:
return fetched.pipe(output, { end: true })to:
fetched.on('error', err => output.destroy(err))
return fetched.pipe(output, { end: true })Or use
stream.pipeline(fetched, output, () => {}) instead, which forwards errors and cleans up the source stream by design.
**How to apply:** Since the fix is inside the npm package, use patch-package (or pnpm's pnpm patch) to persist the change: edit node_modules/baileys/lib/Utils/messages-media.js the same way, then run npx patch-package baileys. With this patch, the returned stream rejects with TypeError: terminated at the consumer, so your existing try/catch around downloadMediaMessage can catch the failure and retry instead of the process crashing or the message handler stalling silently.
**Defensive coding until patched upstream:** Wrap media downloads with your own timeout (e.g., Promise.race against a timer) since the unpatched stream can hang indefinitely, and add a process.on('uncaughtException') handler as a last resort to prevent the undici error from killing the process. The workaround has been verified in production on Baileys 7.0.0-rc14 with Node 24.
TroubleshootingHow to fix 'Connection Closed' error when sending an image with Baileys right after connecting?
This happens because image uploads call refreshMediaConn(), which queries the socket while the WebSocket may still be in CONNECTING state (readyState=0), causing sendRawMessage to throw Boom('Connection Closed'). Text messages rarely hit this since they need only one round trip. Fix: wait for the socket to fully open before sending media:
await sock.waitForSocketOpen();
await sock.sendMessage(jid, { image, caption });
waitForSocketOpen() resolves once the socket is open, waits if still connecting, and throws if closed/closing. Verified on @whiskeysockets/baileys 6.7.24 — delivery succeeds consistently after adding the wait.
TroubleshootingHow to fix Baileys communityMetadata throwing "Cannot read properties of undefined (reading 'attrs')"?
This bug affects @whiskeysockets/baileys@7.0.0-rc.14 and current master. extractCommunityMetadata() expects a <community> node, but WhatsApp can return a <group> node, so the non-null assertion fails and community.attrs throws.
Immediate workaround: call groupMetadata() with the same community JID. A community JID is a normal @g.us JID, and this returns the needed metadata, including community-related fields:
const meta = await sock.groupMetadata(communityJid)
For description updates, use the group equivalent:
await sock.groupUpdateDescription(communityJid, newDescription)
Permanent fix: update the community metadata parser to accept either response shape and throw a classified error when both are missing:
const community =
getBinaryNodeChild(result, 'community') ??
getBinaryNodeChild(result, 'group')
if (!community) {
throw new Boom('community metadata response carried no <community> or <group> node', {
data: result,
})
}
The same incorrect assumption affects communityUpdateDescription() and communityGetInviteInfo(); communityFetchAllParticipating() may silently return {} for the same reason.
TroubleshootingHow to fix "Cannot read properties of undefined (reading 'id')" in sendMessageAck before login in Baileys?
In Baileys 7.0.0-rc13/rc14, sendMessageAck reads authState.creds.me.id before login, but creds.me is only populated after pairing. Change the call in src/Socket/messages-recv.ts to use optional chaining:
- const stanza = buildAckStanza(node, errorCode, authState.creds.me.id);
+ const stanza = buildAckStanza(node, errorCode, authState.creds.me?.id);
buildAckStanza already handles a falsy meId; pre-login notification ACKs do not require the from attribute. Rebuild the package or use patch-package until the fix is released. This resolves the hidden TypeError and the misleading failed to ack notification { ackErr: {} } log. It does not by itself fix QR pairing or unhandled companion_reg_refresh notifications.
TroubleshootingHow do I fix WhatsApp ERROR 463 when sending one-to-one messages to a phone-number JID that has a mapped LID?
Before sending a 1:1 message to an @s.whatsapp.net PN JID, resolve it through Baileys' local LID mapping: call signalRepository.lidMapping.getLIDForPN(pn). If a LID is returned, send the message to <lid>@lid instead of the PN JID, and preserve the original PN as remoteJidAlt metadata. For example, route 19178056839@s.whatsapp.net to 148373990592755@lid when that mapping exists. This avoids the asynchronous messages.update rejection with messageStubParameters: ["463"] and should produce normal SERVER_ACK/DELIVERY_ACK responses. If no local LID mapping exists, keep the existing PN resolution path rather than forcing an implicit USync. Upstream fixes implement this PN-to-LID resolution in the send/relay path.