Skip to main content

Documentation Index

Fetch the complete documentation index at: https://whiskeysockets-docs-jids-socket-config-ptbr.mintlify.app/llms.txt

Use this file to discover all available pages before exploring further.

Most Baileys problems fall into a small set of categories: connection handling, authentication state, message retry configuration, and media. The sections below cover the most common issues and their fixes.

Common issues

Baileys does not automatically reconnect after a connection is closed — that is intentional. You must handle reconnection yourself in the connection.update event.The key is to check DisconnectReason.loggedOut before retrying. A 401 status code means the user actively logged out and reconnecting will not help — you need a fresh QR code. Any other error is safe to retry:
import makeWASocket, { DisconnectReason, useMultiFileAuthState } from '@whiskeysockets/baileys'
import { Boom } from '@hapi/boom'

async function connectToWhatsApp () {
    const { state, saveCreds } = await useMultiFileAuthState('auth_info_baileys')
    const sock = makeWASocket({
        auth: state
    })
    sock.ev.on('connection.update', (update) => {
        const { connection, lastDisconnect } = update
        if(connection === 'close') {
            const shouldReconnect = (lastDisconnect.error as Boom)?.output?.statusCode !== DisconnectReason.loggedOut
            console.log('connection closed due to ', lastDisconnect.error, ', reconnecting ', shouldReconnect)
            // reconnect if not logged out
            if(shouldReconnect) {
                connectToWhatsApp()
            }
        } else if(connection === 'open') {
            console.log('opened connection')
        }
    })

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

connectToWhatsApp()
Check the DisconnectReason enum for all possible status codes and their meanings.
If the QR code never appears, the most likely cause is that valid credentials already exist in your auth state. When Baileys finds existing credentials on startup, it tries to reconnect silently without generating a QR.To force a new QR code, delete your auth state folder (for example, auth_info_baileys/) and restart. Baileys will then start fresh and print a new QR.If you expect a QR but the socket connects immediately, add a log in connection.update to inspect the full update object:
sock.ev.on('connection.update', (update) => {
    console.log('connection update:', update)
})
printQRInTerminal is marked as deprecated in SocketConfig and may not work in newer versions. If you need QR output, listen for the 'qr' property in connection.update and render it yourself using a package like qrcode-terminal.
WhatsApp’s retry system requires your application to return the original message when a delivery attempt fails. Without this, Baileys cannot retry and the sender sees the “this message can take a while” warning.Implement getMessage in your SocketConfig to fetch a message from your store by its key:
const sock = makeWASocket({
    getMessage: async (key) => await getMessageFromStore(key)
})
getMessageFromStore is your responsibility — it should look up the message by key.id in whatever storage layer you use (in-memory store, database, etc.).For a complete retry setup, also provide msgRetryCounterCache:
import NodeCache from '@cacheable/node-cache'
import { CacheStore } from '@whiskeysockets/baileys'

const msgRetryCounterCache = new NodeCache() as CacheStore

const sock = makeWASocket({
    msgRetryCounterCache,
    getMessage: async (key) => await getMessageFromStore(key),
})
Poll votes are encrypted and arrive as updates in the messages.update event, not as new messages. To decrypt them you need two things:
  1. getMessage implemented in SocketConfig (see above) — Baileys needs the original poll message to decrypt the vote
  2. The getAggregateVotesInPollMessage utility
import { getAggregateVotesInPollMessage } from '@whiskeysockets/baileys'

sock.ev.on('messages.update', event => {
    for(const { key, update } of event) {
        if(update.pollUpdates) {
            const pollCreation = await getMessage(key)
            if(pollCreation) {
                console.log(
                    'got poll update, aggregation: ',
                    getAggregateVotesInPollMessage({
                        message: pollCreation,
                        pollUpdates: update.pollUpdates,
                    })
                )
            }
        }
    }
})
If getMessage returns undefined, the vote will be silently dropped. Make sure your store correctly indexes messages by their full key.
WhatsApp requires audio to be in Ogg format with the Opus codec. Files in other formats will fail to play on some clients, particularly on iOS.Convert your audio with ffmpeg before sending:
ffmpeg -i input.mp4 -avoid_negative_ts make_zero -ac 1 output.ogg
The required flags are:
  • codec: libopus — Ogg/Opus container
  • -ac 1 — mono channel (one channel)
  • -avoid_negative_ts make_zero — fix negative timestamps
Then send the converted file:
await sock.sendMessage(jid, {
    audio: { url: './output.ogg' },
    mimetype: 'audio/mp4'
})
Sending to a group requires Baileys to fetch the group’s participant list to build the encryption envelope. If you do not cache this metadata, Baileys makes a live request to WhatsApp for every message — which is slow and can trigger rate limits.Set cachedGroupMetadata in your SocketConfig and keep the cache warm by listening to group events:
import NodeCache from '@cacheable/node-cache'

const groupCache = new NodeCache({ stdTTL: 5 * 60, useClones: false })

const sock = makeWASocket({
    cachedGroupMetadata: async (jid) => groupCache.get(jid)
})

sock.ev.on('groups.update', async ([event]) => {
    const metadata = await sock.groupMetadata(event.id)
    groupCache.set(event.id, metadata)
})

sock.ev.on('group-participants.update', async (event) => {
    const metadata = await sock.groupMetadata(event.id)
    groupCache.set(event.id, metadata)
})
Missing or stale group metadata is one of the most common causes of group message failures. The cache is strongly recommended for any application that sends to groups.
WhatsApp can log you out of all linked devices if it detects malformed chat state updates. This is most commonly triggered by calling chatModify with incorrect data.
// safe — correct lastMessages data
await sock.chatModify({ archive: true, lastMessages: [lastMsgInChat] }, jid)

// dangerous — passing incorrect or missing fields
await sock.chatModify({ archive: true, lastMessages: [] }, jid) // may trigger logout
Never call chatModify with unverified or incomplete data. If you are unsure of the correct last message, skip the operation rather than guessing. A malformed update can trigger WhatsApp’s security system and force a full re-authentication on all your linked devices.
If your credentials have expired or become invalid, Baileys will emit a connection.update with a DisconnectReason.loggedOut (status 401) close reason. At that point you must start a fresh session:
1

Delete the auth state folder

Remove the folder where you stored credentials (for example, auth_info_baileys/). This forces Baileys to start a new authentication flow.
rm -rf auth_info_baileys/
2

Restart and scan a new QR

Restart your application. Baileys will generate a new QR code for you to scan.
3

Verify you save creds on every update

Make sure you are listening to creds.update and persisting credentials every time it fires — not just on first connection. Failing to save updated credentials is the most common cause of unexpected session expiry.
sock.ev.on('creds.update', saveCreds)
WhatsApp automatically expires media from its servers after a period of time. Once the media URL expires, you will receive a 404 when trying to download it.To recover expired media, request a re-upload from another linked device that still has the file:
await sock.updateMediaMessage(msg)
When downloading media with downloadMediaMessage, pass reuploadRequest so Baileys can automatically handle the re-upload if the original URL has expired:
import { createWriteStream } from 'fs'
import { downloadMediaMessage, getContentType } from '@whiskeysockets/baileys'

sock.ev.on('messages.upsert', async ({ messages }) => {
    for (const m of messages) {
        if (!m.message) return
        const messageType = getContentType(m.message)

        if (messageType === 'imageMessage') {
            const stream = await downloadMediaMessage(
                m,
                'stream',
                { },
                {
                    logger,
                    // pass this so that baileys can request a reupload of media
                    // that has been deleted
                    reuploadRequest: sock.updateMediaMessage
                }
            )
            const writeStream = createWriteStream('./my-download.jpeg')
            stream.pipe(writeStream)
        }
    }
})

Enable full debug logging

When you cannot identify the root cause from the symptoms alone, enable debug-level logging to see every raw WebSocket frame that Baileys sends and receives:
import makeWASocket from '@whiskeysockets/baileys'
import P from 'pino'

const sock = makeWASocket({
    logger: P({ level: 'debug' }),
})
This will print every binary node to the console as structured JSON, including the tag, attrs, and content of each frame. Look for unexpected frames or error tags (such as 'failure' or 'stream:error') that indicate what WhatsApp is objecting to. For more on interpreting these frames, see Extend Baileys with custom functionality.

Get support

If you are stuck on an issue that is not covered here, the community Discord is the best place to ask:

Baileys Discord

Join the Baileys Discord server for community support, bug reports, and announcements.