Message Retries & Anti-Delete
Relevant source files
The following files were used as context for generating this wiki page:
The Message Retries & Anti-Delete systems in the Baileys library are critical components designed to ensure message reliability and persistence in a multi-device environment. The Message Retry system manages decryption failures (Ciphertext errors) by coordinating with the sender to re-request message keys or request a "placeholder resend" from a primary mobile device. This is essential when sessions become desynchronized or pre-keys are exhausted.
The Anti-Delete functionality (often implemented via protocol message interception) monitors for REVOKE type messages. Within the context of this project, it involves identifying and potentially preserving messages that are marked for deletion by the sender. These systems work together to provide a robust messaging experience where technical failures are automatically resolved and user actions like deleting messages can be tracked or mitigated.
Message Retry Management
When a client receives a message it cannot decrypt (resulting in a "Ciphertext" stub), the retry manager handles the negotiation for a new attempt. This involves tracking retry counts, managing temporary caches, and determining if a session needs to be recreated.
Retry Logic and Data Flow
The system uses a combination of local caches and protocol-level receipts to resolve decryption issues. If a message fails to decrypt, the client sends a retry receipt. If the retry count persists, it may trigger an automatic session recreation to refresh cryptographic keys.
The diagram above illustrates the decision logic when a message fails to decrypt, involving retry counts and placeholder requests. Sources: lib/Socket/messages-recv.js:475-525, lib/Utils/message-retry-manager.js
Key Components
| Component | Description | Source |
|---|---|---|
msgRetryCounterCache | A Node-Cache instance storing the number of retry attempts per message ID. | lib/Socket/messages-recv.js:23-26 |
placeholderResendCache | Tracks active requests for placeholder resends to prevent duplicate requests. | lib/Socket/messages-recv.js:33-36 |
sendRetryRequest | Function that constructs and sends a retry receipt, potentially including new pre-keys. | lib/Socket/messages-recv.js:462-550 |
requestPlaceholderResend | Sends a peerDataOperationRequestType.PLACEHOLDER_MESSAGE_RESEND to the primary device. | lib/Socket/messages-recv.js:936-976 |
Session Recreation & Recovery
In cases where standard retries fail (typically after the first attempt), the system can force a session recreation. This is controlled by the enableAutoSessionRecreation configuration.
Session Validation Logic
If enableAutoSessionRecreation is enabled, the messageRetryManager checks if a session exists for the fromJid. If the retry count is high and the session is unstable, the existing session is deleted from the authState.keys, forcing a fresh handshake during the next retry attempt.
Sources: lib/Socket/messages-recv.js:490-505, lib/Utils/message-retry-manager.js
Anti-Delete Mechanism
Anti-delete functionality is primarily driven by the handling of protocolMessage stanzas with a type of REVOKE.
Handling Revocation Nodes
When a message is revoked by the sender, the library identifies the REVOKE type in the protocol message. Technical implementations of Anti-Delete intercept this event before the message is removed from the local database or cache.
The sequence of events when a revocation (delete) message is received. Sources: lib/Utils/messages.js:428-433, lib/Socket/messages-recv.js:630-640
Identification of Revocation
The library uses WAProto.Message.ProtocolMessage.Type.REVOKE to signify a deletion request. The extractMessageContent function is used to drill down into these protocol messages to find the target message key being deleted.
Sources: lib/Utils/messages.js:428-433, lib/Utils/anti-delete.js
Placeholder Resend (Primary Device Sync)
A unique feature for multi-device reliability is the "Placeholder Resend" request. If the companion client (the bot) cannot decrypt a message, it can ask the user's primary phone to resend the message data via a Peer Data Operation (PDO).
PDO Request Structure
The request is encapsulated in a peerDataOperationRequestMessage with the PLACEHOLDER_MESSAGE_RESEND type. It includes the messageKey of the failing message.
const pdoMessage = {
placeholderMessageResendRequest: [{
messageKey
}],
peerDataOperationRequestType: WAProto.proto.Message.PeerDataOperationRequestType.PLACEHOLDER_MESSAGE_RESEND
}
Sources: lib/Socket/messages-recv.js:965-971
Configuration Summary
The behavior of these systems is governed by several parameters in the SocketConfig.
| Parameter | Type | Default / Range | Description |
|---|---|---|---|
maxMsgRetryCount | number | Variable | Maximum number of times a retry receipt will be sent for a single message. |
retryRequestDelayMs | number | Variable | Delay between the decryption failure and sending the retry request. |
enableAutoSessionRecreation | boolean | Optional | Whether to delete and recreate sessions on persistent retry failures. |
Sources: lib/Socket/messages-recv.js:10-15, lib/Socket/chats.js:37-40
Summary
The Message Retry and Anti-Delete systems provide a failsafe against the inherent complexities of Signal-protocol-based multi-device messaging. By managing retry receipts, refreshing pre-keys via uploadPreKeys, and utilizing Peer Data Operations for placeholder resends, the client maintains high message delivery success rates even during session desynchronization. Simultaneously, the handling of protocol REVOKE messages allows the system to monitor and manage message deletions effectively.