Troubleshooting

Diagnose by symptom. Almost everything below maps to a disconnect code or a wiring mistake โ€” both are fixable in minutes once you know which.

Disconnect codes โ€” the master table

Read the code from lastDisconnect.error.output.statusCode, or let classifyDisconnect() do it (full table). The codes themselves:

CodeNameCauseFix
401loggedOutThe phone unlinked the device, or the session was invalidatedPair again. Delete stale creds first if it repeats. Do not auto-reconnect โ€” you'll loop forever
403forbiddenAccount restricted/banned, or the number is blocked from the platformStop everything. Check the account in the phone app; appeal there if applicable
408timedOut / connectionLostNetwork drop, server hiccup, or the host sleptReconnect with a delay. If constant, check the host's network and keep-alive settings
411multideviceMismatchSession/device data out of sync with the accountDelete auth state, pair again
428connectionClosedThe server closed the socket (very common, usually transient)Reconnect with a small delay
440connectionReplacedAnother process/session connected with the same credsFind and kill the other instance. Two bots sharing one auth folder will fight forever
500badSessionCorrupt session files (often a process killed mid-write โ€” atomic writes since v1.0.2 prevent new cases)Delete auth state, pair again, update to โ‰ฅ 1.0.2
515restartRequiredServer requests a fresh connection โ€” normal right after pairingReconnect once. Only a problem if it loops (then treat as badSession)
503unavailableServiceWhatsApp-side outage/degradationBack off and wait it out

"Waiting for this message" on recipients' phones

Cause: the recipient's client asked your bot to re-send a message it couldn't decrypt, and your socket has no getMessage hook (or the store didn't have the message). Fix: wire the store as shown in Store & Sessions, and make sure store.bind(sock.ev) runs for every socket you create โ€” including after reconnects.

Pairing code rejected, QR works

Causes, in order: (1) the number isn't in clean international format โ€” digits only, no +, no leading 0, no spaces; (2) the code was requested before the socket was ready or entered after it expired โ€” request a fresh one and enter it promptly; (3) an ancient base version with the old key derivation. AunuBaileys' derivation is PBKDF2 per the current protocol (verified against the reference), so on a current release, check the number format first.

Bot replies to old messages / replies twice

Cause: you're handling messages.upsert with type: 'append' (history catch-up) as if it were live, or a previous socket is still connected after a reconnect. Fix: filter type !== 'notify', and on reconnect, end/destroy the old socket (sock.ev.destroy(), sock.end()) before creating the new one. Full discussion on the Events page.

Buttons don't render for some users

Cause: interactive/native-flow content renders inconsistently on iOS-paired devices. Fix: send builder output through sock.aunuHandler.sendInteractive() โ€” it detects creds.platform === 'ios' and falls back to plain text automatically, and accepts { forceFallback: true, fallbackText } when you want to force it. Details on the Builders page.

Channel (newsletter) media arrives broken

Cause: pre-1.0.2 upload paths. Fix: update to โ‰ฅ 1.0.2 โ€” channel media now uses the dedicated newsletter paths with server thumbnail/transcode. See Newsletters.

Socket hangs during connect / pre-key upload stalls

Cause: fixed in v1.0.2 โ€” pre-key uploads gained a 30-second timeout. On older bases the socket could wait forever. Update.

Store is empty after every restart

Cause: the store is in-memory by design โ€” nothing persists unless you save it. Fix: persist store.toJSON() on an interval and store.fromJSON() at startup; the exact pattern is on the Store page. Your session persisting fine while the store resets is expected โ€” they're different things.

Group adds throw 429 with AunuAntiBan

Cause: that's the guard working (default 3 adds per group per 10 minutes). Fix: space the adds out, or deliberately raise groupAddMax/groupCreateMax in the AntiBan options. Don't remove the wrapper to make the error go away โ€” the platform's version of this limit doesn't come with an error message.

Everything works locally, dies on the server

Usual causes: the host suspends the process (keep-alive + a process manager like PM2/systemd), the auth folder isn't on persistent disk (containers!), or two deployments share one session (โ†’ 440). Persist the auth folder, run one instance, supervise the process.