fix(realtime): tie channel join_ref to the actual join push ref - #1627
Merged
Merged
Conversation
RealtimeChannel.subscribe() sent the phx_join message with join_ref hardcoded to None, then set self.join_ref to a brand-new, unrelated ref generated *after* the join succeeded. Every later push on the channel (leave, broadcast, presence track/untrack) therefore carried a join_ref that never matched any ref the server had actually seen, defeating its purpose: letting the server detect stale messages after a rejoin. Newer Phoenix versions rely on this and silently drop pushes that don't line up. Fix: generate the join ref once, use it as both `ref` and `join_ref` on the phx_join message, and store that same value as channel.join_ref. Fixes SDK-1526
Tr00d
approved these changes
Sep 10, 2026
spydon
approved these changes
Sep 10, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Follow-up to #1626 for the
v3branch (different realtime implementation, same class of bug, different root cause).RealtimeChannel.subscribe()sent thephx_joinmessage withjoin_refhardcoded toNone, then setself.join_refto a brand-new, unrelated ref generated after the join succeeded. Every later push on the channel (leave, broadcast, presence track/untrack) carried ajoin_refthat never matched any ref the server had actually seen for that channel — defeating its purpose of letting the server detect stale messages after a rejoin. Newer Phoenix versions rely on this and silently drop pushes that don't line up.Fix: generate the join ref once in
subscribe(), use it as bothrefandjoin_refon thephx_joinmessage, and store that same value aschannel.join_reffor subsequent pushes.Test plan
tests/test_join_ref.py: a local in-process websocket server (same pattern astest_reconnection.py'sRealtimeServer) records every client-sent message and asserts join/broadcast/track/untrack/leave all carry ajoin_refequal to the actualphx_joinref. All 4 fail on unmodifiedv3(confirmed) and pass after the fix.ruff check/ruff format --check: clean.mypy src/realtime tests: clean.pytest tests/: the new tests plus the rest of the fast suite pass.test_connection.py/test_presence.pyneed a local Supabase stack andtest_reconnection.pyhas a pre-existing port-reuse flake (address already in useon::1:55555) — both reproduce identically on unmodifiedv3, unrelated to this change.Fixes SDK-1526