Rubylight Download 2.2.10
On this page
  1. What the stream card warnings mean
  2. Moonlight cannot find or pair with the PC
  3. The console will not open, or a port is occupied
  4. Black picture, no display, or WGC fails
  5. HDR looks washed out, too bright, or different between clients
  6. Audio cuts out or lags
  7. PyroWave shows blurred grey blocks
  8. Low latency is reported, but motion still stutters
  9. The picture freezes while audio and input continue
  10. The picture freezes and the GPU resets during a stream
  11. Playnite does not launch
  12. RTSS does not start, or the game ignores the cap
  13. Monitors stay on, or the display layout does not return
  14. "Virtual display did not become active before the deadline"
  15. The stream disconnects after a second with "os error 10035"
  16. A controller or other input does nothing
  17. Steam shows two controllers
  18. A Steam Deck has no gyro, trackpads or back grips
  19. Setup rejects the profile folder's owner
  20. An update stays queued
  21. Logs and a useful report

Troubleshooting #

Documentation · Getting started · Configuration

Start with the current stream's settings, the console and the logs. Record the time of a failure before changing anything, and change one setting at a time. Capture and performance probes add work to the GPU; use an idle session for those comparisons.

Find a symptom: Pairing · Console or port · Black screen · Audio · Blurred PyroWave · HDR colour · Stutter · Playnite · RTSS · Display restoration · Controllers · Steam Deck · Updates · Logs and support

What the stream card warnings mean #

The stream card shows the active encoder and warnings for the current session. Each warning also writes a WARN log with its cause and a next step. Capture recovery and audio capture warnings clear when those paths recover. Dropped packets, frames and input, and audio device changes, stay on the card for 30 seconds after they last happened. A warning describes a fallback or limitation, not a measured latency penalty.

Moonlight cannot find or pair with the PC #

If the device pairs but cannot launch Desktop, open Devices → Edit and check its enabled state and List apps, View streams and Launch apps permissions. A device missing mouse or keyboard permission can receive video without that input working.

The console will not open, or a port is occupied #

The default base port is 47989; the console uses 47990. A changed Base port moves the console to the next port up. Check the active profile's sunshine.conf if the launcher reports another address.

Start Rubylight.exe reopens the correct console when that profile is already running. If it reports another streaming host on the port, close the conflicting Sunshine, Apollo, Vibepollo or second Rubylight instance, or assign separate profiles and ports. Restarting another copy on the same port does not solve the conflict.

For an installed host, check Rubylight in Windows Services. Its internal service name is ApolloService. If it is stopped, read service.log before starting it again. The log locations below distinguish service and portable profiles.

Black picture, no display, or WGC fails #

  1. On Overview → Host readiness, inspect Screen capture, Video encoder and Virtual display. A physical monitor must be active, or the configured virtual display must be available.
  2. Check Settings → Display → Display and any app/device override. Confirm that the selected display is the one containing the desktop or game.
  3. For service-mode WGC, keep a Windows user signed in. Rubylight starts its WGC capture worker in that user's session. A locked or UAC desktop uses the Desktop Duplication recovery path; WGC is retried when the normal desktop returns. A stream started while Windows is locked sets up its display on the lock screen; if the virtual display cannot be set up there, the stream shows the physical display and the stream card says so. Start the stream again after signing in.
  4. Read the capture backend opened log entry for the backend that actually opened. requested_capture=wgc describes the request and can appear even when capture falls back.
  5. If the virtual-display status reports access denied, use the installed Windows service and check that the bundled driver is ready. A portable host having administrator rights is not equivalent to the driver's service access.

For a controlled comparison, disconnect first, set Settings → Video → Capture method to Desktop Duplication, reconnect at the same resolution/rate, and record whether the symptom changes. Return to Automatic afterward unless the explicit choice is needed. Keep the original failure log so a successful fallback does not hide the WGC error.

HDR looks washed out, too bright, or different between clients #

Separate the host's HDR source, the negotiated stream and the client's display output:

If HDR looks washed out with no HDR badge on the TV, update the host: since 2.0.1 every client gets the HDR state once per stream (#11). Rubylight's native HEVC and AV1 HDR path is checked down to reference pixels; see the native HDR record.

Audio cuts out or lags #

Audio and video share the network path. On Wi-Fi, a video burst can fill the adapter or access point's queue even when the average bitrate looks reasonable. Lost HEVC or AV1 frames can then require a larger recovery frame.

  1. Lower the client's bitrate and compare the same scene. On AMD, HEVC or AV1 is a better starting point for Wi-Fi than PyroWave. Compare a wired connection when possible.
  2. Leave pacing_max_bitrate_kbps at 0 for automatic pacing. Conventional codecs use about twice the encoder bitrate only on confirmed Wi-Fi or mobile broadband routes. Ethernet, loopback, VPN, Tailscale and unknown routes keep the faster 800 Mbps default, subject to a known physical Ethernet link's speed. Hyper-V vSwitches use the bound physical adapter when Windows exposes an unambiguous binding; otherwise they keep the wired default. A host connected by cable cannot automatically account for Wi-Fi between the access point and client.
  3. For that wired-host/wireless-client case, try a positive pacing override around twice the stream bitrate: for example, pacing_max_bitrate_kbps = 120000 for a 60 Mbps stream. Save and reconnect. The setting is in kbps, has a floor of 110% of the stream bitrate, and does not reduce the stream's encoded bitrate. If loss continues, lower the client's bitrate too; pacing cannot create wireless capacity.

Compare Moonlight's loss statistics and the host log before and after. reference_invalidations counts reference-loss feedback separately from idr_requests; neither is a count of lost packets. PyroWave has no inter-frame references, so its recovery feedback does not force another encode or increase FEC. A steadily rising request counter alone does not establish Wi-Fi loss. Pacing details and transport evidence describe the limits of the local tests.

PyroWave shows blurred grey blocks #

A very low bitrate can leave PyroWave with only coarse brightness and little colour or fine detail. The old one-bit-per-pixel warning was too low for the measured desktop pictures. The stream card and log now distinguish PyroWave bitrate is too low (red, below the severe-loss floor) from PyroWave bitrate is below recommended (amber, text and textures may lose detail).

At 60 fps the floor/recommendation are 139/277 Mbps for 720p, 187/399 Mbps for 1080p and 747/1593 Mbps for 4K, rounded up. These come from desktop and game test scenes on AMD, including SDR/HDR and 4:2:0/4:4:4; picture content still decides how clean any one stream looks. The one-pixel text at 720p needed more bits per pixel than the larger text at higher resolutions. Criteria, rates and limits explain the two levels.

Raise the bitrate in Moonlight on a fast wired network with headroom for packet overhead and recovery data. 4K60 at the recommended rate needs more than gigabit Ethernet. If the client or network cannot carry it, use HEVC or AV1. Compare the same scene after changing the rate; the warning does not diagnose packet loss or HDR rendering. NVIDIA users should use Vibepollo.

Low latency is reported, but motion still stutters #

Compare the same moving scene at the same resolution, frame rate, codec and bitrate. A static desktop may legitimately send repeated or fewer frames. Begin with 1080p60 SDR, then change one variable.

Statistic What it helps distinguish
Overview → Frame rate Frames sent by the host. Repeated pictures can still count toward this rate.
Encode (p95) Slower conversion/encoding completions, including asynchronous encoder work.
Host processing Time after the host claims a frame through preparation for transmission.
Frame age Waiting from the capture/presentation timestamp until the host claims the frame.
Moonlight's network and decoder statistics Loss, jitter or client decoding delays after host processing.

None of the host timings measures the complete input-to-screen delay. Smoothness also depends on distinct pictures arriving regularly. The performance guide separates host timings, measured picture age, fresh-picture rate and arrival gaps.

If the problem starts when the GPU is fully occupied, compare with a lower game frame cap or lighter graphics settings. If client network loss rises, reduce bitrate or compare a wired connection. If decoder time rises, reduce resolution/rate or select another hardware-decoded codec. Keep WGC and compute defaults for the baseline; use capture/compute overrides only for a recorded comparison. The published local tests do not establish results for every Radeon model or Wi-Fi connection.

The picture freezes while audio and input continue #

Try AV1 first when the client can decode it in hardware, then HEVC.

Start from the default encoder settings: amd_usage=ultralowlatency, amd_lowlatency_mode=auto, amd_input_queue_size=0, amd_preanalysis=disabled, amd_split_frame=auto and compute_queue_realtime=false. Use amd_smart_access_video=disabled while diagnosing a freeze. Install AMD's current Recommended driver for your card from AMD's driver page.

If the freeze returns, change one setting per reconnect (WGC against Desktop Duplication, then gpu_compute_conversion on against off) and note which one changes the result.

Send the host log from CLIENT CONNECTED through CLIENT DISCONNECTED, plus startup/probe failures and the client log around the failure time. The default Information log level already writes encoder settings, display setup and the 5-second stream timings lines. Debug (min_log_level=debug) adds GPU scheduling and probe details; the change applies right away. Preserve whole lines, including fields. In particular include:

The picture freezes and the GPU resets during a stream #

Windows logs a LiveKernelEvent 141 (VIDEO_ENGINE_TIMEOUT_DETECTED) and the Radeon may stay in Device Manager error Code 31 until a reboot. This is the AMD driver's video encoder hanging inside an encode call. Rubylight's stall watch then logs stream thread stopped making progress with phase=encoding, while its GPU query probe still answers. No host process can end a call blocked in the kernel driver; only Windows' timeout reset does.

If it happens on your PC:

Playnite does not launch #

Keep a Windows user signed in, enable Playnite in Settings → Game library, and check that the game starts in Playnite locally. If Rubylight cannot find a portable copy, leave Playnite open in that user's session when starting the stream.

In Library, check Playnite's plugin status. Use Install plugin or Update plugin if offered, fully exit and reopen Playnite, then try Sync now. Use the connector bundled with Rubylight; newer Vibepollo connectors may require different host support. A Playnite CLI fallback requested warning means automatic game-exit tracking is unavailable; quit that stream manually.

Set Log level to Debug before reproducing so the log includes Playnite plugin check and the launch-pipe details. Send the failure time, installed or portable location, Desktop or Fullscreen mode, and the host log from Playnite launch prepared and Playnite plugin check through the pipe, startup, fallback or exit messages. Include any Moonlight session launch failed, Playnite library sync failed, Playnite startup failed, Playnite did not confirm startup or Playnite game exit confirmed lines. If available, include Playnite's playnite.log and the matching %APPDATA%\Sunshine\logs\sunshine_playnite-*.log.

RTSS does not start, or the game ignores the cap #

Open Maintenance → Frame limiter during the affected stream. Record Configured, Active now, RTSS detection/running state and RTSS folder. A missing tray icon alone does not establish whether the limiter is active.

In Settings → Frame limiting, check Limiter, Frame limit, Virtual display refresh and RTSS folder. None disables limiting. Physical-monitor streams need Limit every stream if you want a cap on every stream; virtual-display policy can apply its own cap. A frame limit of 0 follows the stream rate, including fractional values such as 59.94.

The folder must contain the RTSS executable and its hook library, not just a shortcut. If the log says RTSS requires administrator privileges, start RTSS as administrator before streaming or use Rubylight's installed service. If it is found and running but one game ignores the limit, check that game's RTSS profile and include the game/API in the report. If RTSS's window keeps your own limit during a stream, Rubylight could not reach the elevated RTSS: use the installed service, or run a portable copy as administrator. RTSS 7.3.7 ignores edits of its settings file and takes a new limit only through its own interface, which Rubylight uses from rc.27; the log line "RTSS frame limit applied and verified" names the RTSS version.

Rubylight restores limiter values after the last stream owning the limit disconnects. A game retaining its display must not keep the cap active. If a cap remains, check for another pending or connected stream and keep the before/during/after values with the log.

Monitors stay on, or the display layout does not return #

Check Settings → Display and app/device overrides first. Extended intentionally keeps physical displays alongside the virtual display. Exclusive and isolated layouts have different behavior. A client may also request its own virtual-display arrangement.

Check Restore displays on disconnect, Restore delay and Keep a disconnected display for against the expected lifecycle. An app or retained remote-monitor session may still own a display after video disconnects.

When all streams have ended, use Maintenance → Displays to inspect whether the current layout matches the saved one. Restore saved layout applies that saved layout; Save current layout replaces it with the arrangement you currently want. Saving, restoring and resetting are unavailable during streaming.

Disconnect virtual displays stops every stream and removes Rubylight-created virtual displays. Reset display settings memory forgets pending display changes that Rubylight would otherwise undo. Use those recovery actions deliberately after recording the problem; resetting memory is not the same as restoring a layout.

rc.10 has a brief startup guard for a reproduced case where creating a virtual display reactivated a dormant monitor. Record the client, chosen layout, active monitors and log time when reporting another case.

"Virtual display did not become active before the deadline" #

Up to rc.10, a launch failed with this error when Windows left the new virtual display switched off, typically because it recalled a layout saved for the other connected displays (two TVs in duplicate mode, for example). rc.11 switches the display on itself after a second, without changing the other displays, and logs Windows left the new virtual display switched off; switched it on beside the current displays. Update before trying workarounds such as unplugging the TVs. If a launch still fails, the error says whether Windows reported the display as connected; include that line and the log around it in the report.

The stream disconnects after a second with "os error 10035" #

video sender stopped: A non-blocking socket operation could not be completed immediately. (os error 10035) comes from rc.1, which ended the stream when the Windows send buffer was momentarily full. Since rc.2 the host waits briefly, drops only those packets and keeps streaming, as Vibepollo does; the log then shows UDP send failed; packets dropped at most every five seconds. Install the current release. Frequent drop warnings mean the network cannot carry the bitrate: lower it, or use a standard codec rather than PyroWave over Wi-Fi.

A controller or other input does nothing #

Check the stream card in the console first.

Steam shows two controllers #

Some Steam builds can list one VHF Xbox controller twice. Steam's SDL controller discovery races its XInput and GameInput backends for the same device. Start+Select may then open both Xbox Game Bar and Steam's keyboard. SDL has an upstream fix. Users report that the Steam beta, which includes it, lists the pad once; switch to it under Steam → Settings → Interface → Client Beta Participation. The fix will reach Steam's stable client in a later update.

Steam's logs/controller.txt shows each arrival. Rubylight no longer uses ViGEmBus, which earlier releases offered as a workaround; an installed copy can be uninstalled.

A Steam Deck has no gyro, trackpads or back grips #

The host only follows what Moonlight announces when a controller connects. With Steam Input on for Moonlight, Steam on the Deck gives Moonlight a virtual pad, which has no gyro, trackpads or back grips. On the Deck, disable Steam Input in Moonlight's controller settings in Steam, then reconnect. The stream card says this when the paired device is named Steam Deck and its controller has no gyro. In Rubylight's logs, a Deck that Moonlight sees directly connects with client_type=4.

See Steam Deck.

Setup rejects the profile folder's owner #

An upgrade from 2.2.1 can fail with C:\ProgramData\Butterpollo must be owned by Administrators, SYSTEM or TrustedInstaller. Older installers set the folder's access permissions but could leave an individual user as its owner. Changing access permissions alone does not change ownership.

The fix in 2.2.6 repairs that legacy ownership and the profile permissions during a verified in-place service upgrade, keeping settings and paired devices. Credentials remain restricted to SYSTEM and Administrators. Use the 2.2.6 or later installer and upgrade in the existing installation folder.

Setup still rejects reparse points (including links and junctions) and untrusted parent folders. The repair does not apply to a fresh install or to a damaged installation whose missing or unreadable package manifest forces a full reinstall. If setup still refuses the path, keep the profile backup and include the setup log from the locations below in your report.

An update stays queued #

In Maintenance → Updates, read the current phase and any error. Installation needs the installed Windows service and one minute without streams, pending connections, remote monitors or host apps. Quit a retained Desktop/game session as well as disconnecting its video. A new connection defers the update.

Install updates automatically is opt-in. Include pre-releases controls whether candidates appear, and an update-check interval of 0 disables automatic checks and installation. Manual checks remain available. Portable builds use the release-page download.

Logs and a useful report #

Use Logs → Download log for the host log or Download support bundle for a ZIP containing logs, configuration diagnostics and an available crash dump. Review the contents before posting publicly.

File Default location
Installed host log %PROGRAMDATA%\Butterpollo\config\logs\butterpollo.log
Installed service log %PROGRAMDATA%\Butterpollo\config\logs\service.log
Portable host log Adjacent config\logs\butterpollo.log (2.2.6 or later); otherwise %LOCALAPPDATA%\ButterpolloRust\config\logs\butterpollo.log
Setup log %TEMP%\butterpollo-setup-<timestamp>.log

A custom --config-dir changes the profile location; log_path can override the host log path. The support-bundle download is named butterpollo-support.zip.

The release includes tools\collect_environment.ps1. From PowerShell in the installed or extracted package folder, collect read-only environment evidence with:

.\tools\collect_environment.ps1 -InstallDirectory . -OutputFile "$env:TEMP\butterpollo-environment.json"

Choose a new output filename if that file already exists. The collector records Windows, GPU/driver, physical network-adapter counters, host version/hash and service state. It does not start capture, change settings or upload the report. A source checkout has the same script at rust/tests/collect_environment.ps1.

For a display-specific report, butterpollo.exe --diagnostics prints the detected displays and virtual-driver status without starting a stream. In a portable/user context, its driver-access result may differ from the installed service.

Open an issue with the exact symptom and time, host/client versions, GPU and driver, wired or Wi-Fi connection, resolution/FPS/codec/HDR settings, and the relevant log or support bundle. Include the environment report when the result seems hardware-specific.

View this page on GitHub