Learning objectives
After reading this article you will be able to:
- Identify from the disconnect code why the session dropped
- Fix the common causes: lost session folder, two instances and a removed device
- Build a reconnect routine that does not loop or wipe the session by accident
On this page
- What does it mean when the bot asks for a QR code again?
- How do you read the disconnect reason in Baileys?
- Why does the session vanish on every restart?
- How do you tell if two instances are fighting over the session?
- Did the phone remove the device or go inactive?
- What about whatsapp-web.js?
- How do you stop the session from dropping again?
- How to do this on Square Cloud
- FAQs
Your WhatsApp bot was working, and now the log shows a closed connection or the terminal asks for a QR code again. You scan it, it runs for a few hours or until the next restart, and the cycle repeats. The library is almost never the problem. The session is: the set of credentials that proves to WhatsApp that this linked device is you.
The examples cover Baileys and whatsapp-web.js, the two most widely used unofficial libraries, on the current Active LTS of Node.js with the Baileys 7 API. If you don't have a bot running yet, start with how to make a WhatsApp bot.
What does it mean when the bot asks for a QR code again?#
An unofficial bot connects as a linked device, the same way WhatsApp Web does. On the first pairing, WhatsApp hands over credentials and the library writes them to disk. On later runs it reads them back and connects without a QR code.
Being asked for a QR code again means that, at connection time, there was no valid session. There are only two reasons: the session was not there (folder deleted, different path) or WhatsApp invalidated it (device removed, session replaced). Telling those two apart is the whole diagnosis.
How do you read the disconnect reason in Baileys?#
The connection.update event carries lastDisconnect.error.output.statusCode when the connection closes. These are the codes of Baileys' DisconnectReason enum:
| Code | Name | Meaning | What to do |
|---|---|---|---|
| 401 | loggedOut |
WhatsApp ended this device's session | Delete the folder and pair again |
| 440 | connectionReplaced |
Another connection took over the same session | Find and stop the other instance |
| 500 | badSession |
Corrupted or incomplete credentials | Delete the folder and pair again |
| 515 | restartRequired |
WhatsApp asked for a socket restart | Reconnect |
| 428 / 408 | connectionClosed / connectionLost |
Network drop or timeout | Reconnect with a delay |
Instead of reconnecting blindly, log the code and handle each case. The example below reconnects with a growing delay and gives up only on the codes where retrying cannot help. Set WA_PHONE to the bot's number (digits only, with country code) and AUTH_DIR to the session folder:
import makeWASocket, {
DisconnectReason,
useMultiFileAuthState,
} from "baileys";
const AUTH_DIR = process.env.AUTH_DIR ?? "auth_info";
const PHONE = process.env.WA_PHONE;
let attempts = 0;
async function start() {
const { state, saveCreds } = await useMultiFileAuthState(AUTH_DIR);
const sock = makeWASocket({ auth: state });
let codeRequested = false;
sock.ev.on("creds.update", saveCreds);
sock.ev.on("connection.update", async ({ connection, lastDisconnect, qr }) => {
if (qr && !codeRequested && !sock.authState.creds.registered) {
if (!PHONE) return console.error("Set WA_PHONE to pair.");
codeRequested = true; // qr keeps refreshing; request the code once per connection
console.log("Pairing code:", await sock.requestPairingCode(PHONE));
}
if (connection === "open") {
attempts = 0;
console.log("Connected to WhatsApp.");
}
if (connection === "close") {
const code = lastDisconnect?.error?.output?.statusCode;
console.error("Connection closed. Code:", code);
if (code === DisconnectReason.loggedOut || code === DisconnectReason.badSession) {
console.error(`Invalid session. Delete the ${AUTH_DIR} folder and pair again.`);
process.exit(0); // exit cleanly: a restart-on-error supervisor won't loop
}
if (code === DisconnectReason.connectionReplaced) {
console.error("Another instance is using this session. Exiting.");
process.exit(0);
}
const delay = Math.min(30_000, 1_000 * 2 ** attempts++);
setTimeout(start, delay);
}
});
}
start();The code deliberately leaves the folder alone: wiping the session by mistake is the fastest way to turn a network blip into a new pairing. You decide, by reading the log.
In the dead-end cases (401, 500 and 440), the process exits with code 0, not an error. A supervisor that restarts the bot when it exits with an error, such as a host's automatic restart, would bring it back and start a loop: with the same invalid session on 401 and 500, or kicking out the other instance on 440.
Why does the session vanish on every restart?#
This is the most common cause. The auth folder must live on a disk that survives a process restart. It disappears when:
- The bot runs on a platform with an ephemeral disk that rebuilds the filesystem on every deploy or restart. The whatsapp-web.js docs warn that
LocalAuthneeds a persistent filesystem and does not suit ephemeral hosts such as Heroku. - The path changes: you use a relative path and start the bot from different directories.
- You re-upload the whole project (ZIP or git) and the session folder is overwritten or removed without you noticing.
To check, run the bot, pair, stop the process and run it again. If it asks for a QR code or pairing code once more, the folder is not being read. List the contents of AUTH_DIR before and after the restart: there should be a creds.json and several key files.
For production, the Baileys documentation recommends storing auth state in a database rather than in files, and presents useMultiFileAuthState as a guide for writing that storage. If you keep losing the folder, a database is the way out. The WhatsApp bot 24/7 guide covers the basics of keeping the session on disk.
How do you tell if two instances are fighting over the session?#
The symptom is code 440 (connectionReplaced) and a bot that drops every few seconds. When a second connection uses the same credentials, the earlier one is kicked out. If each instance reconnects on its own, they keep evicting each other.
The usual suspects:
- You left the bot running on your PC and deployed the same one to a server.
- The new deploy starts before the old process dies.
- A process supervisor such as PM2, or a
restart: alwayspolicy, keeps a copy alive that you cannot see. - You copied the session folder somewhere else and ran both.
The fix is to guarantee a single instance per session. If you need to test locally, pair a second test number instead of reusing the production folder.
Did the phone remove the device or go inactive?#
Code 401 (loggedOut) means WhatsApp ended that linked device. Two causes:
- Someone removed the device under Settings, Linked devices, or logged out of the account on the phone.
- The primary phone went unused for more than 14 days. According to the WhatsApp Help Center, the phone does not need to be online for linked devices to work, but they are logged out if you do not use the phone for more than 14 days.
The device limit counts too: the Help Center states how many devices you can link to one account. If you already use WhatsApp Web, the desktop app and other bots on the same number, check the list under Linked devices and remove what you do not use.
In both cases, the only fix is to delete the session folder and pair again. Reconnecting with the old credentials just repeats the 401.
What about whatsapp-web.js?#
whatsapp-web.js stores the session with LocalAuth, which saves browser data to the .wwebjs_auth folder by default. Without an authStrategy, the client persists nothing and asks for a QR code on every run:
const { Client, LocalAuth } = require("whatsapp-web.js");
const qrcode = require("qrcode-terminal");
const client = new Client({
authStrategy: new LocalAuth({
clientId: "main-bot",
dataPath: process.env.AUTH_DIR ?? ".wwebjs_auth",
}),
});
client.on("qr", (qr) => qrcode.generate(qr, { small: true }));
client.on("ready", () => console.log("Connected to WhatsApp."));
client.on("disconnected", (reason) => {
// reason is "LOGOUT" or a WhatsApp Web state such as CONFLICT or UNPAIRED
console.error("Disconnected:", reason);
});
client.initialize();The disconnected event receives "LOGOUT" when the session was ended, or a state such as CONFLICT (another session took over, the equivalent of 440) or UNPAIRED (the device was unlinked). The causes match Baileys: lost folder, two instances, removed device. It adds one of its own: because a Chromium instance runs alongside the bot, running out of memory can crash the browser and take the connection with it. If the process dies without a clear message, check RAM usage first.
How do you stop the session from dropping again?#
- One session, one instance. Never run the same folder in two places.
- Persistent folder, outside your code. Set
AUTH_DIRthrough an environment variable and keep it out of the repository. - Log the code of every disconnect. Without the log you are guessing. With it, diagnosis takes a minute.
- Reconnect with a delay, not in a tight loop. Immediate, endless retries only fill the log and hide the cause.
- Use the primary phone now and then. Open WhatsApp on it at least every two weeks.
- Do not treat an unofficial bot as guaranteed. Unofficial libraries can break when WhatsApp changes its protocol, and using them against the Terms of Service is your risk. For commercial use, compare with the official Cloud API in Baileys, whatsapp-web.js or Cloud API: it uses a webhook and a token and does not depend on a linked-device session.
How to do this on Square Cloud#
Square Cloud is self-service hosting: you upload the bot, choose the memory and control the code. You can host WhatsApp bots built with Baileys, WPPConnect, whatsapp-web.js or the official Cloud API. The auth folder stays on the application's disk, which persists across restarts and deploys, so the session stays connected. A new ZIP overwrites only the files it contains: keep the auth folder out of the ZIP so it isn't replaced.
That removes the most common cause of repeated QR codes: a session that vanishes on every restart. Containers stay on around the clock, and automatic restart, which is on by default when you deploy from the dashboard, brings the process back when it exits with an error. That is why the example exits with code 0 when the session is invalid. You can follow disconnect codes in the real-time logs in the dashboard or the CLI. Each background application, such as a bot, gets at least 256 MB of RAM; if you use whatsapp-web.js with Chromium, reserve more memory.
Set AUTH_DIR and WA_PHONE in the application's environment variables. The one-instance-per-session rule still applies: when you deploy the bot, stop the copy running on your PC. See the details in WhatsApp bot hosting on Square Cloud.
Bot hosting
Keep your bot online 24/7 with automatic restarts
FAQs
Why does my WhatsApp bot ask for a QR code every time it restarts?
Because the auth folder does not survive the restart. That happens on ephemeral disks, on redeploys that recreate the container, or when the code points to a different folder on each run. Store the session on a persistent path.
What does the 401 loggedOut error mean in Baileys?
WhatsApp ended the session for this linked device. It usually means someone removed the device under Linked devices, or the primary phone went unused for more than 14 days. Reconnecting with the same credentials does not help: delete the folder and pair again.
Can I run the same bot on my PC and on a server at the same time?
Not with the same session. The second connection kicks out the first with code 440 (connectionReplaced), and if each one reconnects on its own they keep evicting each other. Use one session per instance.
Does a WhatsApp bot need my phone to stay on?
Linked devices work without the phone being online, but they are logged out if the primary phone goes unused for more than 14 days. Opening WhatsApp on the phone now and then is enough.
More in Bots
See all 33 articles- How much does it cost to host a Discord bot?The cost of hosting a Discord bot depends on RAM, uptime, database and outside services. Learn how to estimate your own bill and where the money goes.
- Running a bot on your phone or PC vs hosting itA bot on your PC or phone (Termux) goes offline when the device shuts down, sleeps or loses its network. Compare the three options and when each one fits.
- How to host a Discord bot 24/7To keep a Discord bot online 24/7, run its process on an always-on machine with automatic restarts. Compare your PC, a VPS with pm2 or systemd, and bot hosting.
- Why your Discord bot keeps going offline (and how to fix it)A Discord bot goes offline when the process dies, the token is invalid, an intent is disabled or memory runs out. Learn to diagnose each cause and fix it.