Description
Syncd.Codec.mix_mutation/2 raises a RuntimeError when it receives a :remove mutation for an index that doesn't exist in the local index_value_map. This crashes the Coordinator GenServer on every fresh pairing during regular_low app-state sync.
Version: 0.1.0-alpha.7
Elixir: 1.19.5-otp-28
Erlang: 28.1
Error
** (RuntimeError) tried remove, but no previous op for index 22ih2vBBdIjulk01vd1PQi/qIdChj611M+cCvLN5I9E=
(baileys_ex) lib/baileys_ex/syncd/codec.ex:170: BaileysEx.Syncd.Codec.mix_mutation/2
(baileys_ex) lib/baileys_ex/syncd/codec.ex:326: BaileysEx.Syncd.Codec.decode_single_mutation/5
Steps to reproduce
- Delete auth state directory (
rm -rf tmp/baileys_auth)
- Pair a fresh session
- Post-pairing 515 restart → reconnect
- Coordinator crashes during
regular_low app-state resync
Analysis
The upstream JS Baileys has the same throw new Boom('tried remove, but no previous op') in mix():
However, in JS the caller in chats.ts wraps decodePatches / decodeSyncdSnapshot in a try/catch (lines 559–620) that:
- Catches the error
- Logs it
- Nulls the collection state (
app-state-sync-version: { [name]: null })
- Retries from scratch (up to
MAX_SYNC_ATTEMPTS)
The BaileysEx Coordinator does not have equivalent error handling around the decode pipeline, so the raise propagates uncaught and kills the GenServer.
Possible fixes
Either:
- (A) Add try/rescue handling in the Coordinator's app-state resync (matching the JS try/catch + retry pattern), or
- (B) Change
mix_mutation/2 to skip the no-op remove gracefully (return gen unchanged) — which is arguably more defensive since Map.delete on a missing key is harmless anyway
Option (A) more closely mirrors JS Baileys. Option (B) is simpler and prevents the error from occurring at all.
Description
Syncd.Codec.mix_mutation/2raises aRuntimeErrorwhen it receives a:removemutation for an index that doesn't exist in the localindex_value_map. This crashes theCoordinatorGenServer on every fresh pairing duringregular_lowapp-state sync.Version: 0.1.0-alpha.7
Elixir: 1.19.5-otp-28
Erlang: 28.1
Error
Steps to reproduce
rm -rf tmp/baileys_auth)regular_lowapp-state resyncAnalysis
The upstream JS Baileys has the same
throw new Boom('tried remove, but no previous op')inmix():src/Utils/chat-utils.tsline 88However, in JS the caller in
chats.tswrapsdecodePatches/decodeSyncdSnapshotin a try/catch (lines 559–620) that:app-state-sync-version: { [name]: null })MAX_SYNC_ATTEMPTS)The BaileysEx
Coordinatordoes not have equivalent error handling around the decode pipeline, so theraisepropagates uncaught and kills the GenServer.Possible fixes
Either:
mix_mutation/2to skip the no-op remove gracefully (returngenunchanged) — which is arguably more defensive sinceMap.deleteon a missing key is harmless anywayOption (A) more closely mirrors JS Baileys. Option (B) is simpler and prevents the error from occurring at all.