#2154·tigervnc

w0vncserver: a compositor-closed PipeWire stream is never reported — the session freezes silently and forever

Author: jamescowensCreated Sep 2, 2026Updated Sep 3, 2026
Labelsbug

Summary

If the compositor destroys the ScreenCast stream while a client is connected, w0vncserver does not notice in any actionable way. It keeps serving a stale framebuffer indefinitely: no error is logged at the default log level, the RFB client is not told, and no attempt is made to renegotiate. The user sees a frozen desktop and eventually a client-side timeout, with nothing in the server log to explain it.

Environment

  • TigerVNC 1.16.0 (w0vncserver), built from release tarball
  • openSUSE Leap 16.0, KDE Plasma / KWin 6.4.2, xdg-desktop-portal-kde 6.4.2
  • NVIDIA proprietary driver, single 4K DisplayPort output, Wayland session

How to reproduce

  1. Start w0vncserver, connect a client, confirm frames are flowing.
  2. Cause the compositor to destroy the stream. The easy way is to make the output disappear: let an external DisplayPort monitor sleep so it drops the link (many do). KWin then has zero outputs, and an output-bound screencast is closed.
  3. The output returns a second later and the local session is completely unaffected.

Observed: the client's picture freezes permanently. w0vncserver sits idle in poll(); ss -tni shows Send-Q 0 and no traffic in either direction. The server log says nothing. Subsequent input calls fail with GDBus.Error:org.freedesktop.DBus.Error.AccessDenied: Invalid session, which is the only hint anything is wrong — and only if the client sends input. A reconnect does not help: the portal session is gone, so it is dead until w0vncserver is restarted.

Expected: the server notices the stream is gone and does something — logs at a visible level, disconnects the client so it can reconnect and renegotiate, or re-requests a stream.

Cause

unix/w0vncserver/pipewire/PipeWireStream.cxx, handleStreamStateChanged():

cxx
  case PW_STREAM_STATE_UNCONNECTED:
    vlog.debug("PipeWire stream disconnected");
    break;

When the compositor tears the stream down, PipeWire transitions the client stream to PW_STREAM_STATE_UNCONNECTED. That is logged at debug level — invisible at the default log level — and then execution simply falls through. Contrast PW_STREAM_STATE_ERROR immediately above, which calls fatal_error(). An unconnected stream is just as fatal to the session in practice: no further frame can ever arrive, because nothing re-creates the stream.

Compounding it: in xdg-desktop-portal-kde the RemoteDesktop session and the ScreenCast session are the same object, so when the stream goes the input half dies too. A client therefore loses video and input together while the server reports neither.

Suggested fix

At minimum, treat PW_STREAM_STATE_UNCONNECTED while a session is active as an error worth surfacing: log at error/notice level, and close client connections so they can reconnect (reconnecting also re-runs the portal negotiation, which does recover). Better still, attempt to re-request the ScreenCast stream, since the compositor's output usually returns within a second.

Silently serving a stale framebuffer forever is the worst of the options, because it is indistinguishable from a network stall and leaves no evidence.

Notes

The trigger here was an external monitor dropping its DisplayPort link on power-save — ordinary hardware behaviour, and something a screencast consumer should survive. We worked around it at the DRM layer (forcing the connector so the output never disappears), but that only avoids the trigger; the silent-freeze behaviour would remain for any other cause of stream teardown (compositor restart, user revoking the portal grant, output reconfiguration).