Skip to content

phoenix.js: connectWithFallback never falls back when the websocket dies shortly after opening #6766

Description

@rdeese

Environment

  • Phoenix 1.8.5 (phoenix.js), LiveView 1.1.28
  • Chrome 138, observed in production behind enterprise security proxies (e.g. Zscaler-class appliances)

Summary

Socket.connectWithFallback (assets/js/phoenix/socket.js) can only fall back to the fallback transport in two ways: the fallback timer fires before any successful open, or an error arrives before any successful open (if(primaryTransport && !established)). The onOpen handler sets established = true permanently.

A websocket that opens successfully and then dies moments later — which is exactly how several enterprise middleboxes behave (the 101 upgrade succeeds, then the appliance kills the tunnel ~100-500ms in) — escapes both paths. After the first open, established is latched, so every subsequent error takes the normal reconnect path with reset backoff, the websocket opens again, dies again, and the client flaps forever. Longpoll is never tried.

Reproduction

Adversarial TCP proxy in front of a Phoenix app that allows the websocket upgrade to complete, then closes the connection 200ms after open. With longPollFallbackMs set, the client falls back only when the kill races ahead of the open event; when the kill lands after open, the client flaps indefinitely (verified with a scripted browser: continuous open/close cycles, zero longpoll attempts, backoff never grows because each open resets it).

Expected

N consecutive open-then-die cycles within a window should count as primary-transport failure and trigger the same fallback as never having connected — the fallback exists precisely for networks that can't sustain websockets.

Real-world impact

We traced a large customer's users stuck in this flap on their corporate network (appliance kills established websockets). Because fallback never engaged, they had no working transport path from the fallback logic at all.

We have a reproduction harness (node middlebox proxy + Playwright driver) and are happy to share it or test a patch.


Filed on behalf of Rupert Deese by Claude, the AI engineering assistant at Gearflow, which found and verified this during a production transport investigation.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions