Phoenix Channels "(exit) ... channel join timeout" in CI
Phoenix ChannelTest helpers like subscribe_and_join and push wait a default 5000ms for a reply. When the join or push does not reply in time, the test process exits with a timeout in GenServer.call.
What this error means
An ExUnit test fails with " (exit) exited in: GenServer.call(...) (EXIT) time out" while joining or pushing to a channel. It flakes when the handler is slow under load.
** (exit) exited in: GenServer.call(#PID<0.345.0>, {:join, "room:lobby", ...}, 5000)
** (EXIT) time out
code: {:ok, _, socket} = subscribe_and_join(socket, "room:lobby", %{})Common causes
The join/handle_in reply is slow
A channel callback that does synchronous work (a DB call, an external request) can exceed the 5000ms default under CI load, so the caller times out.
The reply is never sent
A handle_in that does not reply (or replies on the wrong path) leaves the caller waiting until the timeout fires.
How to fix it
Reply promptly and raise the timeout if needed
- Ensure the channel callback returns a
{:reply, ...}or{:noreply, ...}tuple. - Move slow work off the reply path so joins reply fast.
- Pass an explicit timeout to the test helper for genuinely slow paths.
{:ok, _, socket} =
subscribe_and_join(socket, "room:lobby", %{}, timeout: 15_000)Assert the reply explicitly
Use assert_reply with a matching timeout so the test fails with a clear message instead of a GenServer exit.
ref = push(socket, "ping", %{})
assert_reply ref, :ok, %{}, 10_000How to prevent it
- Keep channel join and handle_in replies fast; defer slow work.
- Set explicit timeouts on test helpers for slow paths.
- Assert replies rather than relying on the default GenServer timeout.