phoenix_live_view icon indicating copy to clipboard operation
phoenix_live_view copied to clipboard

Mobile Tab switching triggers full page reload and error flash

Open sabiwara opened this issue 5 months ago • 46 comments

Environment

  • Elixir version (elixir -v): 1.18.4-erlang-27.3.4.1
  • Phoenix version (mix deps): 1.7.21 (also confirmed on 1.8.0-rc.3)
  • Phoenix LiveView version (mix deps): 1.0.7 (also confirmed on 1.0.17)
  • Operating system: debian-bullseye-20250630-slim
  • Browsers you attempted to reproduce this bug on (the more the merrier): Safari on iPhone
  • Does the problem persist after removing "assets/node_modules" and trying again? Yes/no: yes

Actual behavior

On a freshly created liveview app, when reopening a liveview tab on mobile after a while (switching to tabs/apps in btw or locking/unlocking), a full reload is triggered, losing client state and flashing an error message.

Image

I managed to consistently reproduce it on an iPhone with the following steps (unlocking is more predictable than switching tabs):

  • open the tab
  • lock the phone with the side button
  • wait ~10s
  • unlock the phone

This issue is being discussed on https://elixirforum.com/t/mobile-tab-switching-triggers-full-page-reload-in-liveview-is-this-expected-behavior/71188.

As far as I can tell, older versions of liveview (at least livebeats, released a year ago?) don't seem impacted.

Expected behavior

No full-reload, no error message.

sabiwara avatar Jul 16 '25 00:07 sabiwara

I can't recreate this. Do you have server logs? We show a flash error for loss of connection with either "Something went wrong" or "We can't find the internet" depending if the cause is the client connection or server connection. It makes sense that you could see a flash notice after losing connection (the phone sleeps the js thread or cuts the connection), but it's not clear why you are receiving the server error class. Do you have server logs during this? Also by full refresh to do you mean full LiveView re-mount or literal full browser reload of the page? Note that the browser can at any point decide to cycle out the page from memory and that will necessarily require a full re-render and LV itself has its own failsafe refresh if the connected mount repeatedly fails, so there are a couple ways that could happen.

chrismccord avatar Jul 16 '25 00:07 chrismccord

Hi Chris 👋 Sorry for the imprecise report, indeed there are two different types of errors here:

  1. Something went wrong
  2. We can't find the internet

I've been actually getting both, although the reproduction steps I shared above are recreating case 2. Case 1. appears more randomly and I don't have any consistent way to reproduce it besides randomly switching tabs and waiting. But if I'm not particularly trying, I'd say they're about

The only logs I'm getting for both cases are these, no error:

2025-07-16T11:02:51.931023890Z app[web.1]: 11:02:51.930 [info] CONNECTED TO Phoenix.LiveView.Socket in 36µs
2025-07-16T11:02:51.931100706Z app[web.1]:   Transport: :websocket
2025-07-16T11:02:51.931110907Z app[web.1]:   Serializer: Phoenix.Socket.V2.JSONSerializer
2025-07-16T11:02:51.931148260Z app[web.1]:   Parameters: %{"_csrf_token" => "cSUeWH1IPCEBDgp9PxtsIA9GMgI1PUkYIj-j2zFNSyn6xWYGCrSF_Qyr", "_live_referer" => ..., "_mount_attempts" => "0", "_mounts" => "4", "_track_static" => %{"0" => ..., "1" => ...}, "vsn" => "2.0.0"}

Another info I could share is that I'm located in Japan accessing servers in the EU or US, the latency might be making the issue more likely?

Also by full refresh to do you mean full LiveView re-mount or literal full browser reload of the page?

I assumed it was a full-reload since I confirmed it lost the form state (the email input from the register page generated by phx.gen.auth). To be honest I just confirmed what others have been reporting on the forum thread, but the original issue that lead me in this rabbit-hole was the flash.

It makes sense that you could see a flash notice after losing connection (the phone sleeps the js thread or cuts the connection)

I understand this point, on the other hand it feels like non-optimal user experience: the user has a good internet connection, didn't perform any new action, and is getting displayed an error every time they re-open the tab.

I didn't remember seeing this on older projects (pre 1.0), so I wondered if it was intended or a potential regression.

sabiwara avatar Jul 16 '25 11:07 sabiwara

As written on the forum, I have this isssue for all my applications.

As far as I can tell, older versions of liveview (at least livebeats, released a year ago?) don't seem impacted.

Livebeats also has the issue for me. I'm on android, I see the issue in both firefox and chrome. Reproducing it is much harder, as it involves waiting at least 10 - 30m? while in background. Still, I see it quite often on my own applications.

It's not the "something went wrong" error, but re-establishing connection, takes very long, ca. 5s.

I've captured it on video:

https://github.com/user-attachments/assets/cbf46c0b-0fd0-4554-904b-2c290ccc74af

Video timeline:

  1. Firefox, navigating to it for the first time => very quickly loaded
  2. Chrome, switching to a it in a backgrounded tab => very slow, full refresh
  3. Manual fast refresh on firefox
  4. Manual fast refresh on chrome

I'll try to capture server logs on my own application next time, but I don't think we'll see anything interesting there. I think this is 100% a client side issue.

spicychickensauce avatar Jul 16 '25 12:07 spicychickensauce

Here is the server log when it happened. As suspected, nothing interesting there:

15:54:31.028 [info] CONNECTED TO Phoenix.LiveView.Socket in 37µs
  Transport: :websocket
  Serializer: Phoenix.Socket.V2.JSONSerializer
  Parameters: %{"_csrf_token" => "KUhwcw0....YUyL3s", "_live_referer" => "undefined", "_mount_attempts" => "0", "_mounts" => "0", "_track_static" => %{"0" => "http://192.168.178.85:8042/assets/app-6958dfd4c8eee02208df68ed32cbd02a.css?vsn=d", "1" => "http://192.168.178.85:8042/assets/app-d316bf96b8530e7600e3a8fd72ddf315.js?vsn=d"}, "vsn" => "2.0.0"}

Server sees 37µs, but it was again at least 5s on the client

spicychickensauce avatar Jul 16 '25 13:07 spicychickensauce

It's almost surely something on the client, server logs won't help here. It's tricky because phoenix.js handles the connection (https://github.com/phoenixframework/phoenix/blob/main/assets/js/phoenix/socket.js), but we also have some code in LiveView. I was able to reproduce the 5+ second delay on an Android device, but it does not reproduce once I try to attach chrome for debugging. It also seems to work fine on my iPhone.

Edit: also seen it happening on iOS when switching to Livebeats from another tab after a while.

SteffenDE avatar Jul 16 '25 14:07 SteffenDE

Keep in mind that mobile devices will disconnect web sockets and stop running JS whenever they find appropriate. Depending on your OS configuration, if you are saving battery or not, etc. That would explain the difference in behaviour.

This often means there isn't much we can do because they stop running JS altogether. This issue also happens on regular apps.

josevalim avatar Jul 28 '25 12:07 josevalim

Yeah, we are probably running into battery safer stuff. However,

This often means there isn't much we can do because they stop running JS altogether. This issue also happens on regular apps.

I disagree that we can't do much here. I run a small experiment by adding this to my main js file:

let backgroundedAt = new Date();
document.addEventListener("visibilitychange", () => {
  if (document.hidden) {
    backgroundedAt = new Date();
  } else {
    const backgroundedDuration = new Date().getTime() - backgroundedAt.getTime();
    console.log("Was hidden for", new Date(0, 0, 0, 0, 0, 0, backgroundedDuration).toLocaleTimeString("en-GB")
    fetch("/").then((res) => {
        console.log(res);
    });
  }
});

And here are the logs when it happened again, captured via remote chrome debugging:

Server:

13:57:07.945 request_id=GFcFgCyIhxd-zr4AACbC [info] GET /
13:57:08.097 request_id=GFcFgCyIhxd-zr4AACbC [info] Sent 200 in 152ms

13:57:17.672 request_id=GFcFgnBY3yXQ5agAACfC [info] GET /
13:57:17.823 request_id=GFcFgnBY3yXQ5agAACfC [info] Sent 200 in 150ms

13:57:19.640 [info] CONNECTED TO Phoenix.LiveView.Socket in 45µs
  Transport: :websocket
  Serializer: Phoenix.Socket.V2.JSONSerializer
  Parameters: %{"_csrf_token" => "Pjg8BgRHEVN7I3VmRgMrVGwPIzhfJWIaahYc6tU64tM0-DR76byqmCPB", "_live_referer" => "undefined", "_mount_attempts" => "0", "_mounts" => "0", "_track_static" => %{"0" => "http://192.168.178.85:8042/assets/app-4fc4b9a06edf2c81d3bba51c9c86ec28.css?vsn=d", "1" => "http://192.168.178.85:8042/assets/app-b1f64c67300ac60153fadceecd9bed29.js?vsn=d"}, "vsn" => "2.0.0"}

Client:

13:57:06.767 app.ts:160 Was hidden for 00:12:57
13:57:07.270 app.ts:167 Response {type: 'basic', url: 'http://192.168.178.85:8042/', redirected: false, status: 200, ok: true, …}
13:57:18.045 Navigated to http://192.168.178.85:8042/
13:58:16.812 [Violation] 'message' handler took <N>ms
> 13:57:24.607 socket.js:358 [Violation] 'message' handler took 3472ms
> 13:58:11.558 socket.js:358 [Violation] 'message' handler took 362ms
> 13:58:11.913 socket.js:358 [Violation] 'message' handler took 344ms
> 13:58:15.224 socket.js:358 [Violation] 'message' handler took 2900ms
> 13:58:15.731 socket.js:358 [Violation] 'message' handler took 414ms
> 13:58:17.319 socket.js:358 [Violation] 'message' handler took 805ms
> 13:58:17.663 socket.js:358 [Violation] 'message' handler took 324ms
13:57:24.711 [Violation] Forced reflow while executing JavaScript took 643ms

Observations:

  • JS ran as soon as I unlocked the device
  • Server gets the fetch request a couple of ms later
  • It took pretty much exactly 10s for the it to decide to do a full refresh
  • The WS connection is established immediately after the refresh

So I suspect it should also be possible to reestablish the websocket connection within the timeframe of my manual fetch. I'll probably just add a location.reload(); inside my backgrounded detector to avoid the issue, but I believe liveview should be able to provide a better solution than that.

Very interesting are those [Violation] messages which might be pointing to the source of the issue. I only saw those after enabling 'verbose' log level in chrome dev tools But the code in socket.js there is just this.conn.onmessage = event => this.onConnMessage(event), so I don't know how this can take 3.5 seconds.

spicychickensauce avatar Jul 30 '25 12:07 spicychickensauce

Good point. If I remember correctly, we could not trigger a reconnect while in inactive state. But we may have missed something? Can you try doing so by fiddling with the internals?

We also have a somewhat related issue here: https://github.com/phoenixframework/phoenix/issues/5942

josevalim avatar Jul 30 '25 14:07 josevalim

It's almost definitely something we do wrong in the Phoenix Socket client related to reconnects.

SteffenDE avatar Jul 30 '25 14:07 SteffenDE

Sorry for not being able to contribute much more at the moment. Reading the thread I'd like to suggest using the Performance API to compute durations if we eventually need to in LiveView's JS code.

So instead of

const backgroundedDuration = new Date().getTime() - backgroundedAt.getTime();

Use https://developer.mozilla.org/en-US/docs/Web/API/Performance/now.

This is the equivalent of using a monotonic clock vs wall clock, and is specially relevant on the client side, since we're exposed to a broader variety of quirks compared to a server we control.

(If of any help or inspiration, I contributed related code to Sentry's JavaScript SDK some years ago, e.g., https://github.com/getsentry/sentry-javascript/pull/2441, https://github.com/getsentry/sentry-javascript/pull/2947)

rhcarvalho avatar Jul 31 '25 08:07 rhcarvalho

Hi everyone,

First, I just want to say how much I absolutely love Phoenix LiveView! The developer experience and performance of the library are incredible, and it's been such a pleasure to build with it. Our app, which operates in a government regulated domain, relying heavily on LiveView, especially with forms for improved interactions, validations, etc.

We're starting to see more of our users experience this issue where switching tabs in a browser or moving away from the app on mobile causes a full page reload, losing form data in the process. Naturally, this has been frustrating for them.

I've been experimenting with potential workarounds, for example: listening for the visibilitychange event in JavaScript, saving the form data when the tab becomes hidden, then pushing it back to LiveView via pushEvent to reapply it on the changeset. This helps preserve data, but unfortunately the LiveView still gets replaced because of the full refresh upon reconnection.

I've also tried creating a hook that listens to disconnected() and reconnected() and applying the same idea as above, but without any success.

I'm curious if there are other strategies that could help here or if there's yet been any effort from the Phoenix/LiveView team to investigate a fix for this yet? I'd love to contribute ideas if there's a safe approach that could preserve LiveView state when users temporarily leave and return.

Thanks again for all the amazing work on Phoenix LiveView, it's truly changed how we build real-time apps!

Environment: Elixir 1.18.1 Phoenix 1.7.21 Phoenix LiveView 1.0.9 Debian: bullseye-20241223-slim

markdeleon-dev avatar Oct 02 '25 16:10 markdeleon-dev

Hi @SteffenDE and @rhcarvalho,

Following up on my previous comment, I’ve tried a hook approach where, on disconnected(), I save the form data to sessionStorage, and on reconnected(), I restore it back into the changeset. This preserves form data on the web, but I’m running into issues on mobile where the state isn’t maintained. I’m not sure if it’s because we are using a React Native WebView, but I’ll keep exploring.

By any chance, have either of you experimented with a similar approach or found any workarounds that could help preserve form state across LiveView reconnects on mobile? Any insights would be greatly appreciated!

markdeleon-dev avatar Oct 02 '25 20:10 markdeleon-dev

For forms, I rely on LiveView's automatic recovery mechanism, which depends on a deterministic form ID, and a phx-change event.

https://hexdocs.pm/phoenix_live_view/form-bindings.html#recovery-following-crashes-or-disconnects

rhcarvalho avatar Oct 03 '25 06:10 rhcarvalho

@markdeleon-dev in addition to what @rhcarvalho recommends, this talk is great for making form rescistent to disconnects Link

rmand97 avatar Oct 03 '25 19:10 rmand97

In case of a full page reload, the form recovery won’t help. The issue here is that nobody found a reliable way to reproduce this yet, so it’s very hard to do something about it :(

SteffenDE avatar Oct 03 '25 22:10 SteffenDE

Please try https://github.com/phoenixframework/phoenix/pull/6534 in your app if possible, I believe this should fix the long reconnection attempts!

SteffenDE avatar Nov 13 '25 18:11 SteffenDE

That's great news! I'll give it a go. But the nature of the issue makes is a bit tricky to know if it is fixed, so it will probably take some time to build confidence that it actually is fixed. I'll report back after a trial period

spicychickensauce avatar Nov 14 '25 09:11 spicychickensauce

@SteffenDE Unfortunately, I have already seen the issue again on Chrome on Android. So the PR did not fix the issue 😢

I suspect that the visibilitychange event just isn't triggered when the tab isn't backgrounded, but instead chrome itself is put in the background. The PR might still be an improvement, as I haven't seen the issue for firefox, though there hasn't been enough time yet to confirm this.

spicychickensauce avatar Nov 14 '25 12:11 spicychickensauce

@spicychickensauce hmm I'm seeing visibilitychange triggered reliably when the tab is backgrounded for Chrome on Android. If you have USB debugging enabled, you could try to connect your phone and go to chrome://inspect on your PC to debug the page. If you set debug: true in the LiveSocket options, you should see "Not reconnecting as page is hidden!" being logged after a while. But you can also do window.addEventListener("visibilitychange", (e) => console.log(e, document.visibilityState)) and you should see the events.

SteffenDE avatar Nov 14 '25 12:11 SteffenDE

@SteffenDE Ok, this time I enabled debug and managed to capture it happening via remote debugging. Note that I do not see the "Not reconnecting ..." message.

I have added spaces to clearly separate long time spans in the log below. As you can see, it took 7 seconds to do a full reconnect:

15:00:36.950 socket.js:184 receive: ok phoenix phx_reply (8) {status: 'ok', response: {…}}
15:01:07.913 socket.js:184 push: phoenix heartbeat (undefined, 9) {}
15:01:07.936 socket.js:184 receive: ok phoenix phx_reply (9) {status: 'ok', response: {…}}


15:38:45.037 socket.js:184 push: phoenix heartbeat (undefined, 10) {}
15:38:45.039 socket.js:184 transport: close CloseEvent {isTrusted: true, wasClean: true, code: 1000, reason: '', type: 'close', …}
15:38:45.040 socket.js:184 channel: error lv:phx-GHfkTtwl0kmsWgUD undefined


15:38:52.047 Navigated to http://192.168.178.85:8042/
15:38:52.076 socket.js:184 push: lv:phx-GHfkTtwl0kmsWgUD phx_leave (4, 11) {}
15:38:52.076 socket.js:184 channel: leave lv:phx-GHfkTtwl0kmsWgUD undefined
15:38:52.077 socket.js:184 channel: close lv:phx-GHfkTtwl0kmsWgUD 4 undefined
15:38:52.176 socket.js:184 push: lv:phx-GHfmbE422YsumwbD phx_join (4, 4) {redirect: undefined, url: 'http://192.168.178.85:8042/', params: {…}, session: 'SFMyNTY.g2gDaAJhBnQAAAAIdwJpZG0AAAAUcGh4LUdIZm1iRT…AAVGA.bmf-uhwB2YpNHZws0b4xH1sQ5IirYH1soIW1J_KqsnQ', static: 'SFMyNTY.g2gDaAJhBnQAAAADdwJpZG0AAAAUcGh4LUdIZm1iRT…ABUYA.DFqQlVUjYQM7kmyp-ZfBEewPyOYc9btnWe-GwF2nV_A', …}
15:38:52.225 socket.js:184 transport: WebSocket connected to ws://192.168.178.85:8042/live/websocket?_csrf_token=KQwTVBQbc3snLVsJHQM9KnYfMmoSMlgVbUZ5XZEMjNcyPvDBOEC3bxuQ&_track_static%5B0%5D=http%3A%2F%2F192.168.178.85%3A8042%2Fassets%2Fcss%2Fapp-bb6ca10d205e9dee04777df73bfde2b8.css%3Fvsn%3Dd&_track_static%5B1%5D=http%3A%2F%2F192.168.178.85%3A8042%2Fassets%2Fjs%2Fapp-b049d6c530a2aa7e06380da187bb1482.js%3Fvsn%3Dd&_mounts=0&_mount_attempts=0&_live_referer=undefined&vsn=2.0.0 undefined
15:38:52.264 socket.js:184 receive: ok lv:phx-GHfmbE422YsumwbD phx_reply (4) {status: 'ok', response: {…}}
15:38:52.310 socket.js:184 receive:  lv:phx-GHfmbE422YsumwbD diff  {0: {…}, c: {…}}

spicychickensauce avatar Nov 14 '25 14:11 spicychickensauce

Could it be you are still serving the wrong version of the asset? Maybe node_modules is using a cache or similar?

josevalim avatar Nov 14 '25 14:11 josevalim

Do you see visibilitychange firing when you add the custom listeners?

SteffenDE avatar Nov 14 '25 14:11 SteffenDE

(Note that you need to use the "sd-reconnect-visibility-assets" branch, not "sd-reconnect-visibility"!)

SteffenDE avatar Nov 14 '25 14:11 SteffenDE

I can confirm I am on the "sd-reconnect-visibility-assets" branch. I'm not sure how I can truly confirm it's serving the right file, but I believe it is. This time I've added the visibilitychange listener, which actually does show up, so that's not it... But I still got a reconnect after 10 seconds:

16:33:19.882 socket.js:184 receive:  lv:phx-GHfpZRmIykOECgLF diff  {0: {…}, c: {…}}
16:33:30.865 app.ts:45 Event {isTrusted: true, type: 'visibilitychange', target: document, currentTarget: Window, eventPhase: 3, …} 'hidden'
16:33:49.900 socket.js:184 push: phoenix heartbeat (undefined, 8) {}
16:33:49.921 socket.js:184 receive: ok phoenix phx_reply (8) {status: 'ok', response: {…}}
16:34:20.903 socket.js:184 push: phoenix heartbeat (undefined, 9) {}
16:34:20.926 socket.js:184 receive: ok phoenix phx_reply (9) {status: 'ok', response: {…}}


16:48:46.419 app.ts:45 Event {isTrusted: true, type: 'visibilitychange', target: document, currentTarget: Window, eventPhase: 3, …} 'visible'
16:48:46.425 socket.js:184 push: phoenix heartbeat (undefined, 10) {}
16:48:46.426 socket.js:184 transport: close CloseEvent {isTrusted: true, wasClean: true, code: 1000, reason: '', type: 'close', …}
16:48:46.427 socket.js:184 channel: error lv:phx-GHfpZRmIykOECgLF undefined


16:48:56.076 Navigated to http://192.168.178.85:8042/
16:48:56.101 socket.js:184 push: lv:phx-GHfpZRmIykOECgLF phx_leave (4, 11) {}
16:48:56.101 socket.js:184 channel: leave lv:phx-GHfpZRmIykOECgLF undefined
16:48:56.102 socket.js:184 channel: close lv:phx-GHfpZRmIykOECgLF 4 undefined
16:48:56.211 socket.js:184 push: lv:phx-GHfqPyKePKHbhATF phx_join (4, 4) {redirect: undefined, url: 'http://192.168.178.85:8042/', params: {…}, session: 'SFMyNTY.g2gDaAJhBnQAAAAIdwJpZG0AAAAUcGh4LUdIZnFQeU…AAVGA.sA8CwwC2O442qEZm7g3Fb5WdOA1xPYBhdSZReiniMJw', static: 'SFMyNTY.g2gDaAJhBnQAAAADdwJpZG0AAAAUcGh4LUdIZnFQeU…ABUYA.TEu8PQ1_sQnh00YpkEg5JMglbM0CdnfzhkVq3eI55ko', …}
16:48:56.242 socket.js:184 transport: WebSocket connected to ws://192.168.178.85:8042/live/websocket?_csrf_token=ATMzCHkKBgN0CHIvKBAtMFcQHjgCE3wJJjzi5K059kJ_eeTXnJoarYQM&_track_static%5B0%5D=http%3A%2F%2F192.168.178.85%3A8042%2Fassets%2Fcss%2Fapp-bb6ca10d205e9dee04777df73bfde2b8.css%3Fvsn%3Dd&_track_static%5B1%5D=http%3A%2F%2F192.168.178.85%3A8042%2Fassets%2Fjs%2Fapp-26989dc463d3f6d2891e1b2c0bbc41e9.js%3Fvsn%3Dd&_mounts=0&_mount_attempts=0&_live_referer=undefined&vsn=2.0.0 undefined
16:48:56.269 socket.js:184 receive: ok lv:phx-GHfqPyKePKHbhATF phx_reply (4) {status: 'ok', response: {…}}
16:48:56.314 socket.js:184 receive:  lv:phx-GHfqPyKePKHbhATF diff  {0: {…}, c: {…}}
16:49:00.016 app.ts:45 Event {isTrusted: true, type: 'visibilitychange', target: document, currentTarget: Window, eventPhase: 3, …} 'hidden'

spicychickensauce avatar Nov 14 '25 15:11 spicychickensauce

Maybe you have a package.json so you use phoenix JS from npm? As you see the visibilitychange firing, it seems like something prevents your app from loading the correct Phoenix JavaScript.

Please try https://github.com/SteffenDE/phx-reconnect-example-tmp, which is a fresh setup and check if you see the log there. I configured it already to listen on all IPs + Port 4000, so I guess for you it will be http://192.168.178.85:4000.

SteffenDE avatar Nov 14 '25 16:11 SteffenDE

I do not use phoenix from npm, my package.json only has tailwindcss + iconfiy. I will try your example repo tomorrow and see if I can still get the error there 👍

spicychickensauce avatar Nov 14 '25 16:11 spicychickensauce

@SteffenDE Here is the output I get of your example app on chrome on android. The "not reconnecting ..." message doesn't appear in the log. I did see the error flash + a full refresh. It only took 1 second for it to refresh, but I also only had it in background for 10m. I think how long it takes to do the full refresh depends on how long it was backgrounded.

Navigated to http://192.168.178.85:4000/posts
11:16:17.854 socket.js:184 push: lv:phx-GHgmrMbwpwa0zAMH phx_join (4, 4) {redirect: undefined, url: 'http://192.168.178.85:4000/posts', params: {…}, session: 'SFMyNTY.g2gDaAJhBnQAAAAIdwJpZG0AAAAUcGh4LUdIZ21yTW…ABUYA.rQm1ZG-NpQ8D1x6Yrg0IXsGBaU7lhq7h1LD36nUcqgI', static: 'SFMyNTY.g2gDaAJhBnQAAAADdwJpZG0AAAAUcGh4LUdIZ21yTW…ABUYA.xoKuOzxA7RwibO-oEAoYc6govsvMzmDJL-FNzO1QacU', …}
11:16:17.963 socket.js:184 transport: WebSocket connected to ws://192.168.178.85:4000/live/websocket?_csrf_token=JiMAXCxhfFZUGxMae1ghEmA-PSEvQC07kzQ1N-LdljEYBmWD9hmlamWt&_track_static%5B0%5D=http%3A%2F%2F192.168.178.85%3A4000%2Fassets%2Fcss%2Fapp.css&_track_static%5B1%5D=http%3A%2F%2F192.168.178.85%3A4000%2Fassets%2Fjs%2Fapp.js&_mounts=0&_mount_attempts=0&_live_referer=undefined&vsn=2.0.0 undefined
11:16:17.964 socket.js:184 push: phoenix heartbeat (undefined, 10) {}
11:16:17.987 socket.js:184 receive: ok lv:phx-GHgmrMbwpwa0zAMH phx_reply (4) {status: 'ok', response: {…}}
11:16:18.001 socket.js:184 receive: ok phoenix phx_reply (10) {status: 'ok', response: {…}}
11:16:18.001 socket.js:184 transport: connected to primary after 37
11:16:47.994 socket.js:184 push: phoenix heartbeat (undefined, 12) {}
11:16:48.012 socket.js:184 receive: ok phoenix phx_reply (12) {status: 'ok', response: {…}}
11:17:18.996 socket.js:184 push: phoenix heartbeat (undefined, 13) {}
11:17:19.019 socket.js:184 receive: ok phoenix phx_reply (13) {status: 'ok', response: {…}}


11:28:29.591 socket.js:184 push: phoenix heartbeat (undefined, 14) {}
11:28:29.595 socket.js:184 transport: close CloseEvent {isTrusted: true, wasClean: true, code: 1002, reason: '', type: 'close', …}
11:28:29.595 socket.js:184 channel: error lv:phx-GHgmrMbwpwa0zAMH undefined


11:28:30.419 socket.js:184 transport: WebSocket connected to ws://192.168.178.85:4000/live/websocket?_csrf_token=JiMAXCxhfFZUGxMae1ghEmA-PSEvQC07kzQ1N-LdljEYBmWD9hmlamWt&_track_static%5B0%5D=http%3A%2F%2F192.168.178.85%3A4000%2Fassets%2Fcss%2Fapp.css&_track_static%5B1%5D=http%3A%2F%2F192.168.178.85%3A4000%2Fassets%2Fjs%2Fapp.js&_mounts=0&_mount_attempts=0&_live_referer=undefined&vsn=2.0.0 undefined
11:28:30.420 socket.js:184 push: lv:phx-GHgmrMbwpwa0zAMH phx_join (17, 17) {redirect: undefined, url: 'http://192.168.178.85:4000/posts', params: {…}, session: 'SFMyNTY.g2gDaAJhBnQAAAAIdwJpZG0AAAAUcGh4LUdIZ21yTW…ABUYA.rQm1ZG-NpQ8D1x6Yrg0IXsGBaU7lhq7h1LD36nUcqgI', static: 'SFMyNTY.g2gDaAJhBnQAAAADdwJpZG0AAAAUcGh4LUdIZ21yTW…ABUYA.xoKuOzxA7RwibO-oEAoYc6govsvMzmDJL-FNzO1QacU', …}
11:28:30.421 socket.js:184 push: phoenix heartbeat (undefined, 18) {}
11:28:30.705 socket.js:184 receive: ok phoenix phx_reply (14) {status: 'ok', response: {…}}
11:28:30.751 socket.js:184 receive: ok lv:phx-GHgmrMbwpwa0zAMH phx_reply (17) {status: 'ok', response: {…}}
11:28:30.762 socket.js:184 receive: ok phoenix phx_reply (18) {status: 'ok', response: {…}}
11:28:30.762 socket.js:184 transport: connected to primary after 341
11:29:01.011 socket.js:184 push: phoenix heartbeat (undefined, 20) {}
11:29:01.155 socket.js:184 receive: ok phoenix phx_reply (20) {status: 'ok', response: {…}}

spicychickensauce avatar Nov 15 '25 10:11 spicychickensauce

Image

Which version of Android and Chrome do you use? For me, with Android 16 and Chrome 142.0.7444.159 I see the "channel: error ..." around 5-10 seconds after switching to another app or locking the device. Then, 1 second later I get the "not reconnecting" message. I have another Android device with Android 14, but I cannot test with it at the moment because of the Cloudflare outage...

SteffenDE avatar Nov 18 '25 14:11 SteffenDE

Just to clarify: I'm not saying that the red flash won't be visible at all - I'm also seeing it sometimes, but I'm not seeing it for longer than a brief moment and the page does not do a full refresh, but only reconnects the socket, so any form values are kept.

So from your log, the only thing that stands out to me is that the channel: error message is only seen after you wake it up again (if I understand the log correctly, you put it to sleep some time around 11:17 and woke it up at 11:28:29). Phoenix then waits for a bit until it reconnects, which is expected.

SteffenDE avatar Nov 18 '25 14:11 SteffenDE

I'll leave this open to collect more feedback for now.

SteffenDE avatar Nov 19 '25 18:11 SteffenDE