Breaking changes
is_on_whatsapp rejects unsupported JID types (#817)
Passing a non-PN/non-LID JID (group, newsletter, etc.) to contacts().is_on_whatsapp() now returns an error immediately. Previously the method silently dropped those JIDs with a warn! log, making it easy to miss the ignored input.
is_on_whatsapp contain only Jid::pn(...) or Jid::lid(...) values.
IqError::UnexpectedResponseType added (#817)
IQ responses whose type attribute is neither result nor error (e.g. get, set, or absent) now produce IqError::UnexpectedResponseType { got: Option<String> } instead of being silently accepted. If you exhaustively match on IqError, add an arm for this variant. It is classified as a transient keepalive failure.
New fields
Per-subprotocol error fields onIsOnWhatsAppResult and UserInfo (#817)
The usync response parser now preserves server-returned per-subprotocol errors instead of silently omitting the associated field. Both result types gain new Option<UsyncSubprotocolError> fields:
IsOnWhatsAppResult gains:
contact_error— server error for the contact lookup subprotocollid_error— server error for the LID resolution subprotocolbusiness_error— server error for the business-info subprotocol
UserInfo gains:
lid_error,status_error,picture_error,business_error,devices_error
UsyncSubprotocolError is a new public type:
lid, status, picture_id, etc.) will be None / false / empty. Check *_error when you need to distinguish “not returned” from “server refused”.
Both structs are #[non_exhaustive]; add .. to any exhaustive struct destructuring that matches them.
Fixes & hardening
Device-list and LID batch queries degrade per user (#817)DeviceListSpec and LidQuerySpec now skip individual users whose <devices> or <lid> subprotocol node contains an error, rather than letting that error propagate and fail the entire batch. A server-side per-user error (e.g. a temporarily unavailable device list for one noisy participant) no longer blocks sends to the rest of the group. A result-level devices subprotocol error is demoted to a warn! log rather than an abort, matching WA Web behavior.
App-state MAC validation ignores hasMissingRemove bypass (#817)
hasMissingRemove was previously used to skip snapshot and patch MAC validation when a REMOVE mutation was missing its prior value, matching a misread of WA Web’s behavior. WA Web actually tracks this flag only as telemetry for MAC-failure diagnostics and always rejects MAC mismatches. The bypass is removed; MAC mismatches are now fatal regardless of hasMissingRemove.
Retry receipts: peer-device retry without recipient is aborted (#817)
A retry receipt from a peer device (your own linked device) that omits the recipient attribute has no resolvable target chat — WA Web returns null in this case. Previously the library logged a warning and fell back to from.to_non_ad(), which would produce a failing message lookup anyway. The receipt is now silently dropped rather than proceeding with a wrong chat target.
Retry key bundles require a one-time prekey for regular retries (#817)
Regular retry receipts (non-FBID-bot) must include a <key> (one-time prekey) child in the <keys> bundle. Bundles missing the one-time prekey are now rejected with an explicit error. The exception is primary @bot FBID bot retries, which follow WA Web’s bot_retry parser path and may proceed with identity + signed prekey alone.
Rejected key bundles abort retry resend (#817)
When a <keys> node is present but the key bundle is rejected (e.g. ADV validation failure, missing prekey), the retry resend is now aborted immediately. Previously the code logged a warning and continued, potentially sending with a stale or wrong session.
AD-JID decoder rejects unknown domain type bytes (#817)
The binary-protocol AD-JID decoder now returns a parse error for domain type bytes that do not map to a known server (the WA Web decodeJidU behavior). Previously unknown bytes silently mapped to PN, masking malformed protocol frames.
ADV NoAccountKey log downgraded to debug (#817)
The log emitted when a companion device’s pre-key bundle or retry bundle omits account_signature_key and no stored account identity is available has been downgraded from warn to debug. This server shape is legitimately common when no account identity has been cached yet; the warn level created noise without being actionable.