Error Codes & Troubleshooting

Complete reference of error codes, their causes, and solutions.

DisconnectReason — Status Codes

All connection errors are wrapped in Boom from @hapi/boom. Check the status code via error.output.statusCode.

CodeConstantCauseSolution
401 DisconnectReason.loggedOut Session expired, manual logout, or account logged in on another device. Delete auth folder and re-pair. Do not auto-reconnect.
403 DisconnectReason.forbidden Account banned or temporarily restricted by WhatsApp. Check WhatsApp Web. If banned, cannot be recovered. If temp ban, wait.
408 DisconnectReason.timedOut Connection timeout — server did not respond within the expected interval. Auto-reconnect. Check internet stability.
408 DisconnectReason.connectionLost Keep-alive failed — server did not respond to pings. Auto-reconnect. Check network.
428 DisconnectReason.connectionClosed Connection closed by server or WebSocket error. Auto-reconnect. If frequent, check proxy/network stability.
440 DisconnectReason.connectionReplaced Another device connected with the same account. If intentional, ignore. If not, change WA password.
500 DisconnectReason.badSession Corrupt session — Signal keys or auth data are damaged. Delete auth folder and re-pair. Session cannot be recovered.
503 DisconnectReason.unavailableService WhatsApp server overloaded / under maintenance. Reconnect with longer delay (5-10s). Do not spam reconnect.
515 DisconnectReason.restartRequired Server requests connection restart. Normal after first successful pairing. Auto-reconnect. This is part of the pairing flow.
411 DisconnectReason.multideviceMismatch Account has not joined Multi-Device beta. Open WhatsApp → Linked Devices → Multi-Device beta → Join.

Stream Errors

Errors sent by the server via <stream:error>. Usually appear before disconnect.

CodeMessageCause & Solution
401not-authorizedInvalid session. Delete auth & re-pair.
403forbiddenAccount restricted. Check WhatsApp Web.
404item-not-foundResource not found (usually internal).
405not-allowedAction not permitted.
409conflictSession conflict — another device connected.
500internal-server-errorWA internal server error. Try reconnecting.

Media Upload / Download Errors

CodeCauseSolution
SUCCESS (200)Media retry successfulNothing to do
GENERAL_ERRORGeneral error during media re-downloadRetry updateMediaMessage
NOT_FOUNDMedia no longer on server (expired)Ask sender to resend
DECRYPTION_ERRORDecryption key corruptedAsk sender to resend
400Invalid media URL or missing directPathVerify the message actually contains media

Pairing Errors

CodeCauseSolution
408QR timeout — not scanned in timeRequest new QR/code
500Pairing failed — key mismatchRetry pairing
400Invalid phone number formatUse international format without +

Message Send Errors

CodeCauseSolution
463MessageAccountRestriction — account temporarily restrictedWait a few hours. Don't spam. Check fetchAccountReachoutTimelock
479Server rejected message (tctoken / privacy)Usually auto-handled. Check logs if frequent
408Media upload timeoutRetry with larger mediaUploadTimeoutMs
500"All encryptions failed"Check Signal sessions. May need session re-sync

Error Handling Best Practices

import { Boom, DisconnectReason, delay } from '@mataram/wa'

const handleDisconnect = async (lastDisconnect) => {
  const error = lastDisconnect?.error
  const statusCode = error?.output?.statusCode

  switch (statusCode) {
    case DisconnectReason.loggedOut:
      console.error('Session expired. Re-pair required.')
      return false
    case DisconnectReason.badSession:
      console.error('Corrupt session. Delete auth folder.')
      return false
    case DisconnectReason.restartRequired:
      console.log('Restart required, reconnecting...')
      return true
    default:
      console.log('Reconnecting in 3s...')
      await delay(3000)
      return true
  }
}

sock.ev.on('connection.update', async ({ connection, lastDisconnect }) => {
  if (connection === 'close') {
    const shouldReconnect = await handleDisconnect(lastDisconnect)
    if (shouldReconnect) start()
  }
})

Debugging Tips

Account Restrictions

WhatsApp has several mechanisms to restrict accounts it deems spammy. Understanding these is critical so your bot doesn't get silently limited.

Error 463 — SenderReachoutTimelocked

Account has a reachout timelock. Unlike a ban, this is temporary (usually 24-72h). WhatsApp will reject messages to new contacts (1:1) because the privacy token (tctoken) is withheld. Existing chats remain safe since they already carry a tctoken.

@mataram/wa automatically detects this error when receiving a NACK from the server and calls fetchAccountReachoutTimelock() to update the status. Do not keep sending while restricted — retrying only makes it worse.

Error 479 — SmaxInvalid (Stale Session)

Server rejected the stanza due to a stale device session or incorrect stanza addressing. Usually occurs when the Signal session has expired or there's a mismatch between the registered device and the server. @mataram/wa auto-handles this by recreating the session or re-sending the stanza with the correct session.

Check Restriction Status

MethodPurpose
sock.fetchAccountReachoutTimelock() Check if the account has a reachout timelock, the enforcement type, and when it ends. Emits a connection.update event with the reachoutTimeLock field.
sock.fetchNewChatMessageCap() Check the new chat quota per cycle. Returns total_quota, used_quota, and capping_status (NONE / FIRST_WARNING / SECOND_WARNING / CAPPED).

Message Retry Mechanism

@mataram/wa has an automatic retry system for messages that fail to send. These configs can be set during socket init:

ConfigDefaultPurpose
maxMsgRetryCount 5 Maximum retry attempts per message. Beyond this limit, the message won't be retried.
enableRecentMessageCache true Cache recent messages in memory so they can be re-sent on retry. Disable if you need to save memory.
enableAutoSessionRecreation true Automatically recreate the Signal session if it's corrupt/expired during retry. Prevents error 500 "All encryptions failed".

When retry count > 1 and enableAutoSessionRecreation is on, @mataram/wa automatically checks the Signal session to the target JID. If the session is corrupt or missing, it will be recreated before the retry attempt. This helps avoid reconnect spam — especially with error 479 (smax-invalid) which usually resolves after a session recreation.

← Back Home →