Same issue here on AMD / RADV, so this does not look NVIDIA-specific: it seems to be in the Linux vrlink Vulkan encode path itself.
System
VK_KHR_video_encode_h265), 4 slicesSymptoms
Reset video stream because we had a stream reset request [wgpReset:N != lastReset:M] lines within a few ms, followed by Skipping ResetVideoStream because we have one pending.NumDroppedFrames: 1848.vrlink: ASSERT: "pFrame->ulVideoTimeline == ulTimelineSequence" at /data/src/vrlink/driver_vrlink/videovulkan.cpp:1641.The wireless link is healthy during the resets. I sampled iw dev <adapter> link and station dump once per second while the resets were happening:
Throughput drops at the same time as a reset burst. This was a 60 s test with the headset connected to the adapter's 6 GHz network only; I removed the home 5 GHz network from the headset. Numbers are host TX per 5 s:
adapter TX 254.8 Mbit/s resets +0
adapter TX 82.6 Mbit/s resets +211 <- burst
adapter TX 258.0 Mbit/s resets +3
Ethernet TX 0.0 Mbit/s throughout (nothing goes over the LAN / 5 GHz path)
There were 502 resets in 60 s across two bursts. So the second network is not the cause: all video goes over the adapter, and the host briefly stops sending, as reported above.
Ruled out
Received event indicating network change only at startup, and the resets keep coming with no such events.Other setup notes that may help someone:
skip - channel disabled for 6135 MHz. iw reg set PL plus WIRELESS_REGDOM in /etc/conf.d/wireless-regdom fixed that.wpa-psk, but the headset AP is SAE-only. I changed it to key-mgmt sae, pmf required.PIPEWIRE_LATENCY=2048/48000 %command%.I can provide full logs if useful.
Follow-up:
Thanks for the detailed confirmation! Since this reproduces on AMD/RADV too (and the assert shows up at videovulkan.cpp:1641 vs 1643 on my build), this is clearly not NVIDIA-specific but in the Linux vrlink Vulkan Video encode path itself. I've updated the title accordingly.
Also thanks for the PipeWire tip, I tried PIPEWIRE_LATENCY=2048/48000 %command% (VR headset and PC) but it didn't help in my case... The audio crackling only happens during the video freezes, so on my system it's a symptom of the same stream reset storms (audio is carried in the vrlink stream), not a separate PipeWire underrun issue.
Second data point, different hardware and display server: this reproduces on NVIDIA RTX 4080 / driver 595.91.07, kernel 7.0, X11 (the original report is Wayland/KDE on a 3090). Same signature, including the videovulkan.cpp:1643 assertion.
Host
-pipewire -vrlinkforceenablertw89_8852cu, firmware 0.27.125.0, USB 3 link at 5000M (behind a motherboard hub)Session 2026-09-26 23:41:38 → 23:51:50 (10.2 min of gameplay)
Reset video stream lines in 61 bursts (~45/min, largest burst 21 resets)Warning: Skipping ResetVideoStream because we have one pending.ASSERT: "pFrame->ulVideoTimeline == ulTimelineSequence" at .../videovulkan.cpp:1643. at 23:46:04.631Warning: retransmit request for unknown message N (frame number=N)Bursts start cold — there is no host-side error preceding them, only an incoming reset request, and the acknowledged frame number freezes while the resets repeat:
23:45:33.094 Reset video stream because we had a stream reset request [wgpReset:113 != lastReset:112]
23:45:33.095 SVLFEC::ReportStreamReset() (m_iLastAcknowledgeFrameNumber = 37395)
23:45:33.117 Reset video stream because we had a stream reset request [wgpReset:117 != lastReset:113]
23:45:33.117 Warning: Skipping ResetVideoStream because we have one pending.
23:45:33.145 SVLFEC::ReportStreamReset() (m_iLastAcknowledgeFrameNumber = 37396)
23:45:33.280 SVLFEC::ReportStreamReset() (m_iLastAcknowledgeFrameNumber = 37412)
23:45:33.300 SVLFEC::ReportStreamReset() (m_iLastAcknowledgeFrameNumber = 37412)
Note wgpReset:117 != lastReset:113 — the reset counter jumps by 4, so reset requests are arriving coalesced or going missing.
Impact, measured by the compositor
Total.......... 54205 presents. 2485 dropped. 0 reprojected
Timed out. 32 total
4.6% dropped frames, matching the felt micro-stutters; the 32 timeouts are the moments video drops out entirely.
Confirming the link is not the cause
Per-second iw station dump and iw event for the whole session:
| Signal | −36 to −64 dBm |
| tx retries | 0 |
| tx failed | 0 |
| tx bitrate | mean 1199 Mbit/s, lowest 490 Mbit/s |
| Throughput on adapter | mean 170, peak 317 Mbit/s |
| Scans during gameplay | 0 (all 21 scans fell before 23:40:39 or after 23:52:44) |
| Disconnects / channel switches during gameplay | none |
And not a host capacity limit
Encoder utilisation mean 23%, peak 31%; GPU mean 58%. Nothing is saturated.
The symptom profile differs from the original report
The original describes freezes of ~1–2 s every 20–60 s. What this host shows is more frequent and mostly much shorter — perceived as micro-stuttering rather than distinct freezes, with a handful of full dropouts on top.
Measured over the 61 bursts:
| Burst duration, median | 0.31 s |
| Bursts shorter than 0.5 s | 34 of 61 (55%) |
| Bursts longer than 2 s | 17 of 61 (longest 5.0 s) |
| Interval between bursts, median | 5.5 s (mean 8.5 s, max 68 s) |
So the resets arrive roughly every 5 s rather than every 20–60 s, and most are sub-half-second. (Burst duration here means the span of reset requests; it is not necessarily a continuously frozen image, since frames do get through in between.)
Separately, adapter throughput collapsed from its normal 170–300 Mbit/s to below 20 Mbit/s on 7 distinct occasions, which is when video visibly dropped out entirely:
23:41:38 2 s, low 0.1 Mbit/s
23:42:24 7 s, low 9.4 Mbit/s
23:43:07 3 s, low 5.5 Mbit/s
23:43:35 1 s, low 16.8 Mbit/s
23:45:45 1 s, low 8.5 Mbit/s
23:49:50 1 s, low 2.9 Mbit/s
23:51:47 1 s, low 3.3 Mbit/s
Radio counters stay at 0 retries / 0 failed through all seven, so the PC simply stops sending.
One difference from the original report: no audio crackling
The audio path stays completely undisturbed here. Steam runs with -pipewire, and vrlink's PipeWire sink logs only 8 state changes in the whole session — all of them before gameplay started (23:39:11, 23:40:12, 23:41:35) or after it ended (23:51:50 onward). During the 10.2 minutes containing all 61 reset bursts there is not a single SVLAudioPipewire state change, and no audio artefacts were heard.
So on this host the video stream resets in isolation, while audio keeps streaming through the bursts. If the audio crackling in the original report is consistent, that may be a second symptom rather than part of the same failure — which would narrow this to the video encode path alone.
On the multi-interface theory from #962
In this session vrlink bound to only two addresses — the adapter link and a link-local IPv6 — and Found primary link FRAME_SUBNET.26 held throughout, with 0 Mbit/s on every other interface. Only 1 of 61 bursts falls within 3 s of a Received event indicating network change. (In an earlier session on the same host, with the LAN, a VPN and two docker bridges also up, vrlink bound to six addresses and the correlation was no better: 1 of 21.) On this host that mechanism does not explain the bursts.
Wi-Fi power save was enabled on the adapter, and disabling it measurably reduces the bursts
Everything was at its defaults for the session above; none of the workarounds from the original report were applied. It turns out that on this distribution "default" means power save enabled on the streaming radio:
/etc/NetworkManager/conf.d/default-wifi-powersave-on.conf with wifi.powersave = 3 (enabled).802-11-wireless.powersave: 0 (default), which falls through to that global value.iw dev <adapter> get power_save → Power save: on, on the interface carrying the video stream.Arch, where the original report comes from, does not ship that conf.d drop-in, so power save is off there by default. That may explain why the symptom profile differs.
I repeated the same title on the same host about an hour later with power save disabled. Everything else identical — same SteamVR instance, same adapter, same room:
| power save on | power save off | |
|---|---|---|
| Gameplay window | 10.2 min | 8.8 min |
Reset video stream |
458 | 324 |
| Resets per minute | 44.9 | 36.9 |
| Bursts | 61 | 50 |
| Burst duration, median | 0.31 s | 0.23 s |
| Interval between bursts, median | 5.5 s | 7.9 s |
| Throughput dropouts (<20 Mbit/s) | 7 | 4 |
videovulkan.cpp:1643 assertions |
1 | 0 |
| tx retries / tx failed | 0 / 0 | 0 / 0 |
Every metric moves the same way — roughly 18% fewer resets, shorter bursts, longer gaps between them, and fewer dropouts. This is one session against one session, so I would call it a consistent signal rather than a proven effect, but the direction is unambiguous and the stutter was noticeably milder.
It does not fix the problem: the bursts continue at a similar character, which is consistent with power save being an aggravating factor on the return path (reset requests and acknowledgements reaching the host) rather than the cause.
One practical note: setting 802-11-wireless.powersave 2 on the Steam-managed profile does not survive. On the next connection the value was back to 0 (default) — the profile appears to be rewritten when Steam brings the adapter up, so the setting has to be applied with iw on the live interface each session. If power save does aggravate this, having Steam write powersave=2 into the profile it manages would help every user on a Debian-derived distribution.
Capture tooling and the full anonymized per-second timeline (radio, throughput, GPU, processes, all SteamVR logs merged) are available on request.
Another data point — reproduces on an AMD APU (Strix Halo / Radeon 8060S, RADV) on Fedora 44, SteamVR 2.17.10 stable (not beta), with the same signature and the same videovulkan.cpp:1643 assertion. The existing reports are discrete GPUs (RTX 3090/4080, RX 7900 XTX) on Arch/Garuda/Mint, so this shows it's not specific to discrete cards, to NVIDIA, or to the beta — it's the Linux vrlink Vulkan HEVC encode path itself.
System
mesa-vulkan-drivers-freeworld)rtw89_8852cu, USB 3)VK_KHR_video_encode_h265), slice count: 4Session (~8 min at 50% render resolution, 2157×2157/eye)
Reset video stream because we had a stream reset request lines, in bursts — peak 128 in a single minute (08:56)Warning: Skipping ResetVideoStream because we have one pending.ASSERT: "pFrame->ulVideoTimeline == ulTimelineSequence" at .../videovulkan.cpp:1643.Total dropped frames: 844 then 476, 0 reprojected (drops show as raw judder); repeated WaitForAcquire timed out (FAILED) storms (2697 / 2695 messages suppressed per 30 s window)Bursts start cold with an incoming reset request, and the acknowledged frame number freezes while resets repeat — same as the other reports:
08:56:00.402 vrlink: Reset video stream because we had a stream reset request [wgpReset:23 != lastReset:22]
08:56:00.402 vrlink: SVLFEC::ReportStreamReset() (m_iLastAcknowledgeFrameNumber = 6086)
08:56:00.406 vrlink: [VideoVulkan] Bitstream header size: 87
08:56:00.420 vrlink: Reset video stream because we had a stream reset request [wgpReset:25 != lastReset:23]
08:56:00.420 vrlink: SVLFEC::ReportStreamReset() (m_iLastAcknowledgeFrameNumber = 6087)
08:56:00.428 vrlink: [VideoVulkan] Bitstream header size: 87
08:56:00.571 vrlink: Reset video stream because we had a stream reset request [wgpReset:26 != lastReset:25]
...
08:56:16.892 vrlink: ASSERT: "pFrame->ulVideoTimeline == ulTimelineSequence" at /data/src/vrlink/driver_vrlink/videovulkan.cpp:1643.
The wireless link is healthy. A iw dev wlan0 station dump during the session showed 0 tx retries, 0 tx failed, signal -63 dBm, 6 GHz channel 37, 160 MHz, HE (Wi-Fi 6E) rates rx ~1921 / tx ~1102 Mbit/s. (I sampled once rather than per-second across a freeze like others did, but there were no retries/failures and no scans/disconnects.)
Two extra notes:
mesa-vulkan-drivers ships without VK_KHR_video_encode_h264/h265 (only royalty-free AV1 encode), so the Frame's HEVC encoder can't initialize. sudo dnf swap mesa-vulkan-drivers mesa-vulkan-drivers-freeworld (and the .i686) fixes the no-video case; the reset storm above is what remains after that.Full vrserver.txt / driver_vrlink.txt available on request.
Same here. RTX 4080 SUPER, driver 610.43.03, SteamVR 2.17.10 stable, Arch with Plasma 6.7.4 on Wayland (in a Proxmox LXC), Half-Life: Alyx native. Same assertion at videovulkan.cpp:1643, every time a few ms after a reset request.
Two sessions with about 4 min of play each: 148 and 225 resets (35 and 56 per minute), short bursts between them, the assertion 1 and 3 times. The link is fine (-45 to -49 dBm, over 1100 Mbit/s).
Side note: vrlink could not load OpenSSL here and did the encryption in software ("OpenSSL EVP (New) AES PERF: 0.000000 MByte/s"), because the sniper runtime has only libcrypto.so.1.1 and vrlink loads libcrypto.so. A symlink fixed it (1612 MByte/s), but the resets stayed the same. Maybe worth to check "AES PERF" in your vrserver.txt.
Another +1
Setup: NixOS 26.05, kernel 7.2, SteamVR 2.18.1 (v1790102919), AMD RX 9070 XT (RADV). Steam Frame over the official wireless adapter (6 GHz), not home Wi‑Fi as the VR path.
Symptom: Headset shows hitching / reset storms. Frame vrlink.txt repeatedly logs SVLCodecV4L2::CheckStuck: > 300ms between our last forward progress. Asking remote side for a new IFrame, then > 800ms → hard reset. That triggers FEC frame-skip / unrecoverable errors and PC Reset video stream / wgpReset storms. PC compositor has also logged WaitForAcquire timed out in earlier sessions.
Why this looks like encode stall, not network: Adapter link stays strong (≈ −44…−52 dBm, multi‑Gbps MCS, 0 tx retries). Same physical play space / radio path: Pistol Whip ~0 FEC retries / ~0.05% drops; Half‑Life: Alyx (even menu) hits tens–hundreds of FEC retries/min and frequent CheckStuck. Same failure signature was previously seen on home Wi‑Fi 6E as well as the Frame adapter.
Tried (did not remove CheckStuck / reset storms): lower Steam Link bitrate/width (e.g. 50 Mbps / 1024 encode width), supersample 1.0, sharpening off. Async/high‑priority queue is now working on this machine (amdgpu CAP_SYS_NICE workaround); stalls persist, so this is separate from async reprojection.
Correction to my power save measurement above. The ~18% improvement I reported (44.9 → 36.9 resets/min) does not hold.
Why it was wrong. I set power save with iw dev <adapter> set power_save off and assumed it stayed off. NetworkManager re-applies the profile's value on every activation, and Steam tears the adapter connection down and back up during a session (state change: activated -> deactivating (reason 'user-requested') — 1 activation and 4 disconnects in one capture). The profile is powersave: 0 (default), so each re-activation turns it back on. Setting 802-11-wireless.powersave 2 on the connection does not survive either — Steam rewrites the profile. Only the global default sticks (wifi.powersave = 2 in conf.d).
Re-measured, sampling get power_save once per second, all on SteamVR 2.18.1 beta with SteamVR freshly started:
| Title | Power save | Play window | Resets/min |
|---|---|---|---|
| Arizona Sunshine | on | 41.4 min | 4.7 |
| Half-Life: Alyx | on | 14.0 min | 5.2 |
| Half-Life: Alyx | off (1082/1082 samples) | 15.6 min | 7.5 |
| Half-Life: Alyx | on | 4.7 min | 10.2 |
| Fruit Ninja VR | on | 5.2 min | 10.7 |
With power save on, the rate varies between 4.7 and 10.7 with nothing else changed. The power-save-off run lands at 7.5, inside that range — session-to-session variance exceeds the effect I claimed.
The old figures were also on 2.17.10, not the beta, so they were never comparable to these. That difference is worth reporting on its own: 44.9 and 36.9 resets/min on 2.17.10 versus 5.2–10.2 on 2.18.1 beta for the same title, with dropped frames down from 4.6% (2485 of 54205 presents) to 0.8%. I can't credit the beta yet, because from that point on I also started shutting SteamVR down fully before each session — a leftover vrserver holds @/steamvr/SteamVR_Namespace and makes the next start hang on Unable to bind server socket errno=98. Beta and fresh start changed together; I'll report back once I've separated them.
Still standing. Debian-derived distributions ship wifi.powersave = 3 in conf.d, and the Steam-managed profile inherits it, so power save is enabled by default on the radio carrying the video stream — and the user can't durably disable it through the profile. Arch, where this report originates, has no such drop-in. Having Steam write powersave=2 into its own profile would remove that inconsistency regardless of whether it affects this bug.
Everything else in my earlier comment — reset counts, the videovulkan.cpp:1643 assertion, compositor frame statistics, clean radio counters, no audio crackling — is unaffected.
same here; many of those in my log:
Mon Sep 28 2026 18:27:58.618998 [Info] - Reset video stream because we had a stream reset request [wgpReset:822 != lastReset:821]
Mon Sep 28 2026 18:27:58.619056 [Info] - SVLFEC::ReportStreamReset() (m_iLastAcknowledgeFrameNumber = 40168)
Mon Sep 28 2026 18:27:58.631267 [Info] - Reset video stream because we had a stream reset request [wgpReset:823 != lastReset:822]
Mon Sep 28 2026 18:27:58.631313 [Info] - Warning: Skipping ResetVideoStream because we have one pending.
Mon Sep 28 2026 18:27:58.634776 [Info] - Reset video stream because we had a stream reset request [wgpReset:824 != lastReset:823]
Mon Sep 28 2026 18:27:58.634813 [Info] - Warning: Skipping ResetVideoStream because we have one pending.
Edit: adding missing System Information
same issue here, basically same specs as RalfN but the non-XT version of the gpu.
Additional reproduction — RTX 5070 (Blackwell), Pop!_OS, COSMIC Wayland (native Vulkan HEVC)
Confirming this on a new GPU/driver combo.
System
7.1.9-x64v3-xanmod1, Wayland, COSMIC desktop595.841782866176[VideoVulkan], slice count 4)vrlink settings already in place (nothing exotic)
driver_vrlink: streamFormatWidth 640, targetBandwidth 30
steamvr: preferredRefreshRate 72, disableAsync true
So this is not high-bitrate / high-res / reprojection. The storm happens anyway.
What the logs show (single ~4.7 min session, 18:25:21–18:30:00)
Reset video stream because we had a stream reset request [wgpReset:N != lastReset:M] in vrserver.txt (~129/min)Warning: Skipping ResetVideoStream because we have one pending.[VideoVulkan] Created vkCreateVideoSessionParametersKHR (encoder session rebuilt on nearly every reset)wgpReset counter reached 859; it jumps by >1 between lines (coalesced/missing requests), same as other reportsulVideoTimeline == ulTimelineSequence assertions this session (intermittent — seen in other sessions)Excerpt:
18:26:56.470 [VideoVulkan] Bitstream header size: 87
18:26:56.485 Reset video stream because we had a stream reset request [wgpReset:183 != lastReset:182]
18:26:56.788 [VideoVulkan] CreateVideoSessionParamaters: slice count: 4
18:26:57.252 Reset video stream because we had a stream reset request [wgpReset:186 != lastReset:185]
18:27:07.559 Reset video stream because we had a stream reset request [wgpReset:201 != lastReset:200]
Symptom
Headset tracks head + both controllers and controller input works fine in-game, but video micro-stutters/freezes constantly — unplayable. Felt as frequent judder and 1–2 s freezes. A different (older) SteamVR build did not stutter on the same host/adapter, but then controllers don't work for the frame.
Possibly relevant
vrlink: OpenSSL Soft (Old) AES PERF: 82.440231 MByte/s — software AES at ~82 MB/s (see @lixsldotnet's note about vrlink failing to load OpenSSL and falling back to soft AES; low throughput here too, though they found the resets persisted after fixing it).Steps to reproduce
-pipewire -vrlinkforceenable, SteamVR started manually first.I may have found very nice solace for everyone here with this issue, basically the dongle power being capped at a low sending power 4 dBm which doesnt happen on Windows, changed and tested and works perfectly! Do let me know if you all have the same findings? more techincal overview below:
Root cause found for the rtw89 host side, with per-packet captures on both ends of the link (host wlan1 egress vs the headset's wlanap ingress, matched by IP ID + length + payload hash) plus the headset's own ath12k firmware counters.
The link is not clean, and iw station dump cannot show it. tx retries / tx failed are not implemented for this USB driver (frames count as acked when the URB completes) nor per station on the headset's ath12k, so they read 0 whatever the air does.
Cause. The Frame hotspot advertises itself as a 6 GHz VLP access point (he_6ghz_reg_pwr_type=2). rtw89 follows the AP's power class and applies the ETSI VLP client limits to the adapter: 7 dBm single chain, 4 dBm per chain for two-chain frames (/sys/kernel/debug/ieee80211/phyN/rtw89/txpwr_table: [reg6_pwr_type] 0, OFDM_2TX 4 dBm). The Windows Realtek driver transmits at the chip maximum (16 / 13 dBm) on the same adapter. The headset therefore hears the adapter 13 dB weaker (data -58 vs -45 dBm, acks -71 vs -51 dBm at the same spot; htt_stats type 10 rssi_in_dbm and last ack signal on the Frame). The MAC layer retransmits constantly, packets queue 20 to 56 ms inside the adapter, and vrlink turns every such stall into a reset storm ending in the videovulkan.cpp assert.
Numbers, one 4.5 min Beat Saber song each (about 6 M packets, 120 Hz, RX 9070 XT / RADV, kernel 7.3.0-rc4, SteamVR 2.18.1 beta, Frame OS 0.4.2):
| stock rtw89 (VLP) | rtw89 with LPI class | Windows 11, same PC | |
|---|---|---|---|
| packets lost | 0.22 % | 0 | ~0 |
| queueing delay p99 | 9.4 ms | 4.4 ms | |
| seconds with a stall > 20 ms (of ~265) | 41 | 2 | 0 |
| stream resets / encoder asserts | 69 / 4 | 0 / 0 | 0 / 0 |
| backtrack resets / retransmit requests | 12 / hundreds | 0 / 0 | 0 / 7 |
Every reset fell in a second where a 50 pps ping over the adapter spiked above 25 ms. The headset's uplink retry counters are identical in every run, including the perfect ones, so the weak uplink the firmware stats suggest is a red herring. Not the cause either: GPU load (same bursts at 64 and 80 %), render scale, TV mirror, auto vs fixed bitrate, USB completion latency (usbmon), power save, the Realtek agg-wait patch from rtw-next (A/B tested, identical).
Fix on the host. A module parameter in rtw89 (regd.c) that overrides the 6 GHz power class for this adapter, set to LPI (16 / 13 dBm, the chip maximum): one hunk plus options rtw89_core reg6_pwr_override=2. I am taking the driver side to linux-wireless; Realtek's pending "take board ID 1 for FW elements 28de/2432" patch (rtw-next 2026-09-30) may also change the power tables for this device. Everyone on rtw89 in this thread is under the same 4 dBm limit.
What is still vrlink's. 20 to 50 ms of extra delay on 0.25 % of the packets becomes a full stream reset, an encoder session rebuild and the assertion. The Windows client rides the same radio, with the same uplink retries, without a single reset. A backtrack window or retransmit budget that tolerates a 60 ms stall would remove the visible stutter even on an unpatched driver.
Secondary: the older static -75 dBm packet-detection threshold of Valve's holo-realtek-firmware-toggles made the adapter deaf on fades here (the current helper uses dynamic PD, which halved the aborts before the power fix), and driver_vrlink.forceBaselineVideoFEC true removed the remaining aborts at a bandwidth cost. Raw captures and the capture tools are available on request.
The driver_vrlink.forceBaselineVideoFEC true has improved things for me, and lowering the stream bandwidth to under 100Mb/s seems to cut down on the chance of the retry storm triggering. couldn't reproduce the low transmit power on rtw89 but did the testing on bazzite 7.2.4-ogc3.1.fc44.x86_64 (64-bit) which may not display those numbers correctly
locally the mac80211 queue isn't dropping anything, but i do see a loss of about 0.22% between the dongle and the frame somewhere. though cutting the loss would only reduce the chance of the storm happening again. will continue to investigate
Confirming this reproduces on a third headset/GPU combo: PICO 4 (not Steam Frame), AMD RX 9070 XT (RADV), Bazzite/Fedora 44, SteamVR 2.17.10.
Same exact mechanism in our log:
HandleUnrecoverableError( 1 )
Warning: Skipping ResetVideoStream because we have one pending. [~330x in ~90s]
Warning: retransmit request for unknown message 1158 (frame number=1174)
SVLFEC::ReportStreamReset() (m_iLastAcknowledgeFrameNumber = 1157) [stuck here while sender is already on 1174]
HandleUnrecoverableError( 2 )
One difference that might help narrow the trigger: in our case this wasn't periodic — it happened once, clustered in a ~90 second window right as we teleported to a new area in Steam Home (and/or changed the render resolution setting around the same time — couldn't fully separate the two), then never recurred for the rest of the session. So it may not require a fixed interval to reproduce — a scene/content change or a mid-session settings change might be enough to trigger a reset that then has a chance to get stuck in this same loop.
Also independently corroborates it's not network-related, via a different method than the iw monitoring above: the same headset, same PC, same network simultaneously streams other OpenXR content perfectly via a different runtime (WiVRn) with zero resets/instability at comparable or higher bitrate. Happy to attach full logs if useful.
Follow-up from the original reporter, testing the rtw89 TX power theory from @Molier. It matches on my side, and with the Canadian regulatory domain the limits are even lower than the ETSI numbers reported above.
Nvidia MSI RTX 3090
Arch / KDE Plasma Wayland
kernel 7.2.6-arch2-1
NVIDIA 615.71.09
Steam Frame Wireless Adapter (28de:2432, in-tree rtw89_8852cu)
regdomain CA (Canada)
SteamVR 2.18.1 beta
Half-Life: Alyx (native Linux, no Proton)
/sys/kernel/debug/ieee80211/phy1/rtw89/txpwr_table:
[Regulatory] IC
[reg6_pwr_type] 0
...
OFDM_1TX - NON_BF BF | 1, 0, dBm
OFDM_2TX - NON_BF BF | -5, 0, dBm
MCS_1TX_160M - NON_BF BF | 7, 0, dBm
MCS_2TX_160M - NON_BF BF | 1, 1, dBm
TX power by rate goes up to 16 dBm, so the adapter transmits 9 to 21 dB below what the chip can do. With the IC (Canada) table, OFDM_2TX is -5 dBm vs 4 dBm reported above for ETSI, so users outside ETSI regions may be hit even harder.
A note about my earlier post, "0 tx retries / 0 tx failed" from iw station dump should be disregarded. As explained above, these counters are not implemented for this USB driver, so they don't prove the link is clean.
| Config | Result |
|---|---|
forceBaselineVideoFEC true, target bandwidth 90 Mb/s |
Stutter unchanged; after ~2 min the headset tore down the session (deauthenticated ... Reason: 3=DEAUTH_LEAVING), dongle reassociated ~6 s later |
forceBaselineVideoFEC true, target bandwidth 150 Mb/s |
109 Reset video stream in 2 min 20 s (~47/min), 0 asserts, no disconnect |
LPI (Low Power Indoor) operation is permitted indoors in Canada under ISED rules for the 6 GHz band, so an LPI override such as reg6_pwr_override=2 should be appropriate for indoor home use here, as far as I understand the rules. It would be worth confirming how the patch handles regulatory domains where LPI is not allowed.
Happy to test the reg6_pwr_override patch or the Realtek board-ID patch as soon as either is available.
I have little to provide here that will help but I am experiencing the exact same behavior others are with an identical hardware setup as @Lukas-tek-no-logic
I experience the issue with
Another data point, FCC regulatory domain — lower limits than both ETSI and IC reported above.
Confirming @Molier's VLP power cap finding on a US system.
[Regulatory] FCC
[reg6_pwr_type] 0
[TX power byrate] up to 16 dBm
[TX power limit]
OFDM_1TX - NON_BF BF | 1, 0, dBm
MCS_1TX_20M_* - NON_BF BF | 1, 0, dBm
MCS_1TX_40M_* - NON_BF BF | 4, 0, dBm
So on FCC the adapter is capped at 1 dBm for OFDM and 20 MHz rates against a 16 dBm chip maximum — a 15 dB gap. That's lower than the 4 dBm reported for ETSI and sits alongside the -5 dBm reported for IC, which suggests the VLP cap affects all three regulatory domains rather than being ETSI-specific.
System: CachyOS, kernel 7.2.8-2-cachyos (also reproduced on stock Arch 7.2.8-arch1-2), RTX 3070, NVIDIA 615.71.09, SteamVR 2.18.2 beta, Steam Frame Wireless Adapter 28de:2432 on rtw89_8852cu, firmware 0.27.129.4.
Symptoms match the thread: continuous retransmission visible in the SteamVR debug overlay's Retry/Unacc bands, over 150,000 retransmits sent in a single session, framerate pinned at 72 against a 90 Hz target, and compositor dropouts where delivery hits zero rather than degrading. Severity scales with scene complexity — a 40-player VRChat instance degrades within seconds, an empty world takes a few minutes. The desktop mirror on DisplayPort stays perfectly smooth throughout, matching the observation above that rendering and compositing are fine.
Ruled out locally: 6 GHz channel and width tuning across every available option with Airport Utility confirming no neighbouring networks on the chosen channel; USB hub vs direct motherboard ports; secondary Wi-Fi card set unmanaged and down; multi-link on and off; render resolution at 150% and 100%; target bandwidth Auto and manual 100 Mb/s; firewall inactive entirely; Valve's frame-dongle-troubleshoot.sh reports no problems as both user and root.
One thing that did help, for a separate symptom: I was getting rtw89_hw_scan_offload failed ret -110 followed by a firmware reload every few seconds. Switching NetworkManager's Wi-Fi backend from wpa_supplicant to iwd eliminated those entirely — confirmed across a full session with no new errors. The stream resets and stuttering continue unchanged, so the scan failures were a separate problem, but it may be worth others trying if they see the same log pattern.
Happy to test reg6_pwr_override when a patch is available.
On Linux (did not measure windows) my 5GHz WiFi outperforms the 6GHz dongle (measured with iperf3), so I just don't use it. I still get all the stream resets with the same logs.
On windows 10 streaming works a lot better, but Half-Life: Alyx has a stream reset on blink/teleport. Choosing a movement mode that does not blink/teleport works around it. I did try it with the dongle on windows, but it worked the same. This could be the same thing mentioned by @bushibot in: https://github.com/ValveSoftware/SteamVR-for-Linux/issues/965#issuecomment-5961903296
I can confirm my dongle is also running in VLP mode. I patched morrownr/rtw89 to let the dongle use full power in order to test if it has any impact (note that [reg6_pwr_type] 1 is LPI, [reg6_pwr_type] 2 is STD but the actual value does not realy matter as long as it isn't VLP), but reset storms continued to happen
This shows that it is not entirely a network problem.
Not sure if the power increase actually improved my situation, but the low power is a bug anyway so at some point would need to be patched properly.
Beat saber only hangs once every minute or so, but half life alyx is completely unplayable for me (9070XT, 9800X3D, 7.2.4-1-MANJARO
).
@WBosonic @Lewin225 @nix70900-bit @Postmortals @miversen33 @APTX thanks for testing. Reading your replies, my first comment left two things unclear i realised. and not really a straightforward patch that i used to get it working. The TX power fix on its own is not the whole setup. Here is what actually runs on my machine which made it work perfectly(0 resets and 0 asserts per Beat Saber song, Alyx playable at 120 Hz), and what would help if you still get storms with all of it in place.
useful slop below and if you guys still have similar symptons, post your debug logs etc from the last point 4. below?:
1. The patch. Against v7.3-rc4, drivers/net/wireless/realtek/rtw89/regd.c. If the hunks do not apply to your kernel, the two blocks are easy to place by hand in rtw89_reg_6ghz_power_recalc().
@@ -1129,6 +1129,14 @@ static bool __rtw89_reg_6ghz_power_recalc(struct rtw89_dev *rtwdev)
return true;
}
+/* Explicit 6 GHz power class for the Steam Frame adapter (28de:2432).
+ * 0 = follow the AP (default), 1 = VLP, 2 = LPI, 3 = SP.
+ */
+static int reg6_pwr_override;
+module_param(reg6_pwr_override, int, 0644);
+MODULE_PARM_DESC(reg6_pwr_override, "6 GHz power class override: 0 follow AP, 1 VLP, 2 LPI, 3 SP");
+
static int rtw89_reg_6ghz_power_recalc(struct rtw89_dev *rtwdev,
struct rtw89_vif_link *rtwvif_link, bool active,
unsigned int *changed)
@@ -1171,6 +1179,13 @@ static int rtw89_reg_6ghz_power_recalc(struct rtw89_dev *rtwdev,
rcu_read_unlock();
+ if (active && reg6_pwr_override >= 1 && reg6_pwr_override <= 3) {
+ rtwvif_link->reg_6ghz_power = reg6_pwr_override - 1;
+ dflt = false;
+ rtw89_info(rtwdev, "6 GHz power class forced to %d by reg6_pwr_override\n",
+ rtwvif_link->reg_6ghz_power);
+ }
+
if (!dflt && blocked[rtwvif_link->reg_6ghz_power]) {
Build against the source of your running kernel and install next to the stock modules:
cd <kernel source for $(uname -r)>/drivers/net/wireless/realtek/rtw89
make -C /lib/modules/$(uname -r)/build M=$PWD modules # add LLVM=1 on clang-built kernels (CachyOS)
sudo mkdir -p /lib/modules/$(uname -r)/updates/rtw89
sudo cp rtw89_core.ko rtw89_usb.ko rtw89_8852c.ko rtw89_8852cu.ko /lib/modules/$(uname -r)/updates/rtw89/
sudo depmod -a
echo 'options rtw89_core reg6_pwr_override=2' | sudo tee /etc/modprobe.d/rtw89-frame.conf
Reboot or replug the adapter (a plain module reload can leave it rfkilled). It took effect when dmesg shows 6 GHz power class forced to 1 by reg6_pwr_override and txpwr_table shows [reg6_pwr_type] 1. Rebuild after every kernel update. LPI is the indoor class; it is allowed indoors in the EU, the US and Canada as far as I know. A patched morrownr/rtw89 like @WBosonic used does the same job.
@Lewin225 could you post your txpwr_table with the headset connected? Your 0.22 % loss between adapter and headset is exactly what I measured on the stock driver.
2. The power fix is necessary, not sufficient. @WBosonic is right that it is not only the network. Each of these was measured to matter here:
sudo dmesg | grep BAR=; if it says 256M, turn both BIOS options on. @WBosonic"Beat Saber hangs once a minute, Alyx unplayable" on a 9070 XT is exactly what it looked like here, so this is the first thing I would check.
driver_vrlink.forceBaselineVideoFEC true in steamvr.vrsettings: removed the aborts that were left after the power fix.driver_vrlink.allowMultipleLinks false).rtw89_hw_scan_offload failed ret -110 and a firmware reload, as @Postmortals saw); 7.3 drops that band for this adapter. Switching to iwd avoids the same scans from the other side.3. Not on the adapter? @miversen33 @APTX over home Wi-Fi the rtw89 patch does nothing for you, since the router is the transmitter then. What remains there is the vrlink side from my first comment: a 20 to 50 ms stall becomes a reset storm instead of being absorbed like on Windows (@bushibot's Pico 4 report is the same thing). That part only Valve can fix. The BAR check and the headset scanning still apply.
4. If you still get storms with 1 and 2 in place, this is what would let us tell the adapter, the GPU and vrlink apart:
uname -r, GPU and driver version, SteamVR version and branch, Frame OS version, the gamesudo dmesg | grep -E "BAR=|reg6_pwr_override"sudo cat /sys/kernel/debug/ieee80211/phy*/rtw89/txpwr_table while the headset is connected (the [reg6_pwr_type] line and the [TX power limit] block)sudo dmesg | grep rtw89 after the session (firmware resets, scan failures)driver_vrlink section of ~/.steam/steam/config/steamvr.vrsettingsgrep -c "stream reset request" ~/.steam/steam/logs/vrserver.txt together with the play timevrserver.txt, vrcompositor.txt and driver_vrlink.txt from ~/.steam/steam/logs/ for that session, as an attachment or gist@Molier
Had to implement the driver change slightly differently due to bazzite (Bazzite's 7.2.4-ogc3.1 kernel is built with CONFIG_RTW89_DEBUGFS unset, so /sys/kernel/debug/ieee80211/phy*/rtw89/ doesn't exist)
Did some static testing switching between modes. then over an hour of beat sabre with a script that deauth'd from the headset side, switched radio mode on the desktop and resumed streaming, switching between LPI and VLP randomly
Setup: kernel 7.2.4-ogc3.1.fc44 (Bazzite 44, nvidia-open), RTX 3080 Ti (NVIDIA, so the
ReBAR/amdgpu point doesn't apply), dongle 28de:2432 on rtw89_8852cu fw 0.27.129.4,
USB 3 port on the CPU-integrated controller (not chipset), Frame OS 0.4.3,
SteamVR . No rtw89 scan or firmware errors in the kernel log.
dmesg: "6 GHz power class forced to 1 by| override | Frame hears dongle | dongle hears Frame | asymmetry |
|---|---|---|---|
| 0 follow AP (VLP) | -55 dBm (x2; -57 earlier) | -50 | -5.0 dB (x2; -7.0 earlier) |
| 2 forced LPI | -50 dBm (x2; -52 earlier) | -50 | 0.0 dB (x2; -2.0 earlier) |
LPI minus VLP = +5.0 dB, repeated across three separate windows each way; the dongle-side reading was
constant so position was steady. "power class forced" logged once per LPI association, never for VLP.
Some windows gave no samples (ssh to the Frame failed right after re-association), 4 of 8 valid.
Why +5 and not +9: the Frame's hostapd config (/var/run/softap_hostapd.conf) has he_6ghz_reg_pwr_type=2
(VLP), reg_def_cli_eirp=28 (0.5 dB units, so about 14 dBm EIRP; unit not confirmed) and reg_def_cli_eirp_psd=22.
rtw89 applies the AP's Transmit Power Envelope on top of the power class, so forcing LPI cannot exceed that.
Stock VLP in rtw89 gives about 4 dBm per chain (about 7 dBm total) while the VLP limit is 14 dBm EIRP, so the
driver's VLP tables look conservative; Windows uses the chip maximum (16/13 dBm).
Setup: Beat Saber, 100 Mbit/s, FEC on, headset worn; override 0 (VLP, stock) vs 2 (forced LPI) flipped every 180 s,
random order within each pair, blind, Frame-side deauth at each switch, first 20 s of each block ignored.
Kernel log confirms "power class forced" in every LPI block and none in VLP blocks.
| metric (16 min of each setting) | VLP | LPI | LPI better in | exact paired p |
|---|---|---|---|---|
| storms/min (clusters of resets) | 2.07 | 0.75 | 6/6 pairs | 0.031 |
| Frame unrecoverable errors/min | 5.27 | 1.32 | 5/6 | 0.062 |
| seconds with a >25 ms ping reply | 7% | 3% | 5/6 | 0.22 |
| PC "Reset video stream"/min | 6.71 | 6.33 | 4/6 | 0.97 |
Reading: forcing LPI (+5 dB at the Frame, same-position A/B) cut how often storms START (about 64% fewer) but not
how severe they are once started: a few giant cascades (67 and 27 resets in single LPI blocks) dominate the reset
count, 8.4 resets/storm on LPI vs 3.2 on VLP. That matches the comment's "necessary, not sufficient": vrlink's
recovery is the amplifier.
Caveats: storms/min was chosen after seeing that resets/min did not separate (post hoc; 4 metrics tested);
one player, one game, 6 pairs; per-block resets/min ranged 0.4 to 25.2 on both settings. The Frame-side RSSI
sampling died at the first switch in session 2, so the power check there rests on the kernel log only.
Pushing the dongle to LPI get's it up to 14dBm, which is where it should be on VLP. but after that it's capped by the headset itself asking for VLP correctly. The headset being VLP is correct for something that goes outdoors, but if it could be set to LPI the link should get up to 16dbm (I think... dongle chip's maximum is 16 dBm?)
The frame's hotspot class comes from the Frame's softapmanager, which writes /var/run/softap_hostapd.conf with he_6ghz_reg_pwr_type=2 (VLP) and reg_def_cli_eirp=28 (14 dBm). LPI would mean type 0 and a higher client limit
But it wouldn't stick. That file is regenerated each time the hotspot starts. Might require altering SteamOS for only +2dbm gain and that's only for frame->dongle returns.. just tracking data, no bonus to video
Also. This isn't the real issue this thread is about, when packets are lost the storms still happen, they're just lost less often
Every session on my machine logs this when the adapter connects (in Steam's connection_log.txt / console output):
CRemoteClientDongle: No holo-realtek-firmware-toggles helper script found, low latency mode unavailable
On SteamOS, Steam calls /usr/bin/holo-polkit-helpers/holo-realtek-firmware-toggles set-low-latency-mode on on connect. That helper only ships in SteamOS. The source is public, in holo-main holo-realtek-firmware-toggles 1.3-3. In low latency mode it changes these settings through rtw89 debugfs:
c300/c304/c308/c30c. The script's comment says these are kept "roughly inline with what Steam manually sets on Windows".HW_SCAN and INACTIVE_PS off (disable_dm)Setup: NixOS, kernel 7.2.0, RX 9070 XT (RADV), SteamVR 2.18.2 beta, Frame OS 0.4.3, Steam Frame Wireless Adapter on 6 GHz ch 37 / 160 MHz, regdom NL. Already in place: @Molier's reg6_pwr_override=2 (confirmed [reg6_pwr_type] 1), forceBaselineVideoFEC, automatic bandwidth, allowMultipleLinks false, home Wi‑Fi off on the headset, power save off.
Result in Half-Life: Alyx, about 5 minutes each:
host stream reset request per minute |
|
|---|---|
| everything above, no low latency mode | ~132 (bursts of 100–250) |
| + low latency mode | ~6–7 (8 bursts of 1–7, all recovered) |
The TX-power patch alone did not measurably change the reset rate here. That was 132–289 resets/min over two sessions. Low latency mode on top of it is what made it playable.
I left out two steps. I skipped the static −75 dBm PD threshold because @Molier reported it made the adapter deaf on fades. I skipped the HE-MCS cap because iw set bitrates reportedly oopsed the driver on a 7.3-rc kernel (#946).
Important: the EDCA registers get cleared again, not only on reassociation. In one session they were reset to 0 when the stream session restarted, while the adapter stayed associated the whole time. A one-shot hook on connect isn't enough, so I re-check every 5 s. This needs CONFIG_RTW89_DEBUGFS=y, which many distro kernels don't enable, and debugfs writes are blocked under Secure Boot lockdown.
#!/bin/bash
edca="003F3219" # TXOP 2000us, CWmax 7, CWmin 3, AIFSN 1 (same encoding as the holo helper)
while sleep 5; do
for dev in /sys/class/net/*; do
[[ "$(cat "$dev/device/../idVendor" 2>/dev/null)" == 28de && "$(cat "$dev/device/../idProduct" 2>/dev/null)" == 2432 ]] && break
dev=""
done
[[ -n "$dev" ]] || continue
iface=$(basename "$dev")
[[ "$(iw dev "$iface" link)" == Connected* ]] || continue
d="/sys/kernel/debug/ieee80211/$(basename "$(readlink -f "$dev/phy80211")")/rtw89"
echo "c300 4" > "$d/read_reg"
[[ "$(grep -o '0x[0-9a-f]*$' "$d/read_reg")" == "0x${edca,,}" ]] && continue
echo 0x30 > "$d/disable_dm" # HW_SCAN | INACTIVE_PS off
iw dev "$iface" set power_save off
iw dev "$iface" set tidconf tids 0xff amsdu off
for r in c300 c304 c308 c30c; do echo "$r $edca 4" > "$d/write_reg"; done
echo "applied low latency mode on $iface"
done
What's left: a scene change (an Alyx health station, in my case) can still start a reset storm that vrlink never recovers from. The stream stops and the PC logs Connection inactive for 30 seconds. That looks like the vrlink recovery issue others described.
Request for Valve: could Steam ship this helper, or an equivalent, on desktop Linux? Or at least apply the EDCA values itself, the way it does on Windows?
Managed to have a bunch of solid sessions after
too many packets missing, aborting stream by 98%)RTW89_QUIRK_DISABLE_2GHZ, this solved a nasty crash for me)Did ~ 10 minutes with the low latency script and didn't notice much, but that was in addendum to the above changes. possibly storms down from 1.3 per min to 0.95, but too close to call
Avoiding storms is going to be the key until they're handled better
System:
I see the same Reset video stream because we had a stream reset request / SVLFEC::ReportStreamReset() bursts and 1–2 second freezes.
I specifically tested the network path in three configurations:
The reset storms occur in all three configurations.
With dongle-only I saw an especially large burst where wgpReset increased from roughly 789 to >900 in about two seconds, while the acknowledged frame number stopped progressing.
With the dongle completely removed and the Frame connected through a FRITZ!Box 7530 AX over 5 GHz Wi-Fi 6, I still get repeated reset bursts and eventually Connection inactive.
So in my case this is definitely not specific to the Steam Frame dongle, 6 GHz, or Multi-Link.
I also checked the kernel logs around the failures and did not see NVIDIA Xid errors, GPU resets, USB resets, or other obvious kernel-level faults.
One additional symptom I saw once after a disconnect was:
797:
Assertion Failed in function GetBitRange():
*pEnd > *pStart
GetBitRange(4040 -> 4040)
end is before or same as start
I cannot prove that this assertion has the same root cause as the reset storms, and it does not appear in my normal host-side SteamVR logs, but I wanted to mention it in case it is useful.
One other possibly unrelated finding:
Soft AES PERF: ~30 MB/s
OpenSSL EVP (New) AES PERF: 0 MB/s
OpenSSL Soft (Old) AES PERF: 0 MB/s
So VRLink appears to be falling back to its software AES implementation on my setup as well.
Happy to provide full vrserver.txt / driver_vrlink.txt logs or run additional tests if useful.
Results from the original reporter after applying everything from @Molier's and @RalfN's comments. Linux is now playable here: from ~47 to ~1.8 stream resets/min, with clean audio. Thanks to both of you.
Setup: RTX 3090 (NVIDIA 615.71.09), Arch / KDE Plasma Wayland, kernel 7.2.6-arch2-1 (CONFIG_RTW89_DEBUGFS is enabled on Arch), Steam Frame Wireless Adapter (28de:2432, rtw89_8852cu), regdomain CA, SteamVR [SteamVR version], Frame OS [Frame OS version], Half-Life: Alyx. Resizable BAR is off on this machine (BAR1 = 256 MiB).
The hunks don't apply as-is on 7.2.6, but the two blocks go in the same places by hand: the module_param block right before rtw89_reg_6ghz_power_recalc(), and the override block right after its rcu_read_unlock(), before if (!dflt && blocked[...]). Built against the kernel headers, installed in updates/, options rtw89_core reg6_pwr_override=2. Confirmed with 6 GHz power class forced to 1 by reg6_pwr_override in dmesg.
TX power limits with the IC (Canada) table, ch 47, 160 MHz:
| Stock (VLP) | Patched (LPI) | |
|---|---|---|
OFDM_2TX |
-5 dBm | -1 dBm |
MCS_2TX_160M |
1 dBm | 7 dBm |
Note that the IC table still caps LPI well below the 13–16 dBm reported with ETSI, so users in Canada (and maybe other non-ETSI regions) get less out of the patch.
Resets per minute = Reset video stream count between the first and last reset of each session. Single sessions of ~13–22 min each, so treat small differences as noise.
| Configuration | Resets/min | Notes |
|---|---|---|
| Stock rtw89 (VLP), FEC on, 150 Mb/s manual | ~47 | |
| + TX power patch (LPI), 150 Mb/s manual, no FEC | ~17 to ~35 (4 sessions) | real but modest gain, as @RalfN found |
+ forceBaselineVideoFEC true + automatic bandwidth (native) |
~9 | |
| + Proton Experimental instead of native | ~14 | no crashes, clean audio |
| + @RalfN's low latency script (Proton) | ~1.8 | 23 resets in 13 min, 1 assert, no visible stutter, clean audio |
The low latency script (EDCA registers, disable_dm 0x30, power save and A-MSDU off) made the biggest single difference here too, confirming @RalfN's request: Steam should apply these settings on desktop Linux like it does on SteamOS and Windows. Without them, the desktop Linux experience is far worse than it needs to be.
Settings during the final session: allowMultipleLinks false, forceBaselineVideoFEC true, automaticBandwidth true. The headset's home Wi-Fi stayed on: in my setup the headset would not connect to the adapter without it, so I could not test that variable.
ntfs3 partition, the game crashed after a few minutes with serializedentity.h (797): Assertion Failed in function GetBitRange(), even with a new game. After moving the game to btrfs, that crash was gone.libscenesystem.so (worker thread, no driver frames in the stack), and the audio crackling came and went. Under Proton Experimental: no crash in two sessions (~19 and ~13 min) and no crackling at all.steamwebhelper aborted (SIGABRT) at the end of several sessions; no effect on the game.With all of the above, a few resets remain, and the Windows client on the same hardware has none. As @Molier and @bushibot's Pico 4 report show, a short stall can still trigger a reset loop in Linux vrlink that the Windows client absorbs. That part still needs a fix from Valve.
Tested on 7.2.6-arch2-1 with an RTX 3090. Run everything as your normal user; sudo is used where needed.
0. Prerequisites check
cat /sys/kernel/security/lockdown # must show [none], otherwise debugfs writes are blocked
ls /sys/kernel/debug/ieee80211/ # needs CONFIG_RTW89_DEBUGFS (enabled on Arch)
sudo pacman -S --needed base-devel linux-headers
1. Get the rtw89 source matching your running kernel
V=$(uname -r | sed 's/-arch.*//') # e.g. 7.2.6
cd ~
curl -LO https://cdn.kernel.org/pub/linux/kernel/v${V%%.*}.x/linux-$V.tar.xz
tar -xf linux-$V.tar.xz linux-$V/drivers/net/wireless/realtek/rtw89
cd linux-$V/drivers/net/wireless/realtek/rtw89
2. Apply @Molier's TX power override patch
cat > /tmp/rtw89-reg6.patch << 'EOF'
--- regd.c.orig
+++ regd.c
@@ -1129,6 +1129,13 @@
return true;
}
+/* Explicit 6 GHz power class for the Steam Frame adapter (28de:2432).
+ * 0 = follow the AP (default), 1 = VLP, 2 = LPI, 3 = SP.
+ */
+static int reg6_pwr_override;
+module_param(reg6_pwr_override, int, 0644);
+MODULE_PARM_DESC(reg6_pwr_override, "6 GHz power class override: 0 follow AP, 1 VLP, 2 LPI, 3 SP");
+
static int rtw89_reg_6ghz_power_recalc(struct rtw89_dev *rtwdev,
struct rtw89_vif_link *rtwvif_link, bool active,
unsigned int *changed)
@@ -1171,6 +1178,13 @@
rcu_read_unlock();
+ if (active && reg6_pwr_override >= 1 && reg6_pwr_override <= 3) {
+ rtwvif_link->reg_6ghz_power = reg6_pwr_override - 1;
+ dflt = false;
+ rtw89_info(rtwdev, "6 GHz power class forced to %d by reg6_pwr_override\n",
+ rtwvif_link->reg_6ghz_power);
+ }
+
if (!dflt && blocked[rtwvif_link->reg_6ghz_power]) {
rtw89_debug(rtwdev, RTW89_DBG_REGD,
"%c%c 6 GHz power type-%u is blocked by policy\n",
EOF
cp regd.c regd.c.orig
patch -l regd.c < /tmp/rtw89-reg6.patch
diff -u regd.c.orig regd.c # should show exactly the two added blocks
If patch rejects a hunk on your kernel version, place the two blocks by hand: the first right before static int rtw89_reg_6ghz_power_recalc(, the second right after the rcu_read_unlock(); that precedes if (!dflt && blocked[...]).
3. Build and install next to the stock modules
make -C /lib/modules/$(uname -r)/build M=$PWD modules -j$(nproc)
sudo mkdir -p /lib/modules/$(uname -r)/updates/rtw89
sudo cp rtw89_core.ko rtw89_usb.ko rtw89_8852c.ko rtw89_8852cu.ko /lib/modules/$(uname -r)/updates/rtw89/
sudo depmod -a
echo 'options rtw89_core reg6_pwr_override=2' | sudo tee /etc/modprobe.d/rtw89-frame.conf
modinfo -n rtw89_core # must point to .../updates/rtw89/rtw89_core.ko
A pahole version differs warning during the build is harmless.
4. Reboot (replugging the adapter is not enough if rtw89_core is already loaded), then verify:
cat /sys/module/rtw89_core/parameters/reg6_pwr_override # 2
With the headset connected through the adapter:
sudo dmesg | grep reg6_pwr_override # "6 GHz power class forced to 1"
IF=$(iw dev | awk '/Interface wlp/{print $2}' | while read i; do [ "$(cat /sys/class/net/$i/device/../idProduct 2>/dev/null)" = 2432 ] && echo $i; done)
PHY=$(cat /sys/class/net/$IF/phy80211/name)
sudo grep -E "reg6_pwr_type|OFDM_2TX|MCS_2TX_160M" /sys/kernel/debug/ieee80211/$PHY/rtw89/txpwr_table # [reg6_pwr_type] 1
Note: run sudo grep with $PHY rather than phy*. Your user can't read debugfs, so the shell can't expand the glob.
5. SteamVR settings
With SteamVR closed, edit ~/.local/share/Steam/config/steamvr.vrsettings so the driver_vrlink section contains:
"driver_vrlink" : {
"allowMultipleLinks" : false,
"automaticBandwidth" : true,
"forceBaselineVideoFEC" : true
},
Keep any other keys already in that section, and validate the JSON before starting SteamVR:
python -m json.tool ~/.local/share/Steam/config/steamvr.vrsettings > /dev/null && echo OK
6. @RalfN's low latency script (only change: a timestamp in the log line)
cat > ~/frame-lowlatency.sh << 'EOF'
#!/bin/bash
edca="003F3219" # TXOP 2000us, CWmax 7, CWmin 3, AIFSN 1 (same encoding as the holo helper)
while sleep 5; do
for dev in /sys/class/net/*; do
[[ "$(cat "$dev/device/../idVendor" 2>/dev/null)" == 28de && "$(cat "$dev/device/../idProduct" 2>/dev/null)" == 2432 ]] && break
dev=""
done
[[ -n "$dev" ]] || continue
iface=$(basename "$dev")
[[ "$(iw dev "$iface" link)" == Connected* ]] || continue
d="/sys/kernel/debug/ieee80211/$(basename "$(readlink -f "$dev/phy80211")")/rtw89"
echo "c300 4" > "$d/read_reg"
[[ "$(grep -o '0x[0-9a-f]*$' "$d/read_reg")" == "0x${edca,,}" ]] && continue
echo 0x30 > "$d/disable_dm" # HW_SCAN | INACTIVE_PS off
iw dev "$iface" set power_save off
iw dev "$iface" set tidconf tids 0xff amsdu off
for r in c300 c304 c308 c30c; do echo "$r $edca 4" > "$d/write_reg"; done
echo "$(date +%T) applied low latency mode on $iface"
done
EOF
chmod +x ~/frame-lowlatency.sh
sudo ~/frame-lowlatency.sh # leave it running in a terminal during the VR session
It waits until the adapter is connected, then re-applies the settings whenever the registers get reset. Nothing is permanent: replugging the adapter or rebooting restores the defaults.
7. Game side
GetBitRange assertion there). If Steam's "Move install folder" fails with "Content file locked", quit Steam and move it manually: steam -shutdown
SRC=/path/to/NTFS/SteamLibrary/steamapps
DST=~/.local/share/Steam/steamapps
rsync -a --info=progress2 "$SRC/common/Half-Life Alyx" "$DST/common/"
cp -a "$SRC/appmanifest_546560.acf" "$DST/"
mv "$SRC/appmanifest_546560.acf" "$SRC/appmanifest_546560.acf.bak"
Then start Steam and verify the game files.
8. Measuring (optional)
# Before the session
D=$(LC_ALL=C date '+%b %d %Y'); T=$(date +%T)
# After the session, in the same terminal
LOGS=~/.local/share/Steam/logs
S(){ awk -v d="$D" -v t="$T" '($2" "$3" "$4)==d && $5>=t' $LOGS/vrserver.previous.txt $LOGS/vrserver.txt 2>/dev/null; }
echo "Resets : $(S | grep -c 'Reset video stream')"
echo "Asserts: $(S | grep -c 'ASSERT: "pFrame->ulVideoTimeline')"
S | grep "Reset video stream" | awk 'NR==1{print "First:", $5} END{print "Last:", $5}'
After every kernel update: the patched modules live under /lib/modules/<version>/updates/, so a new kernel silently falls back to the stock driver. Redo steps 1 to 4 with the new version.
To revert:
sudo rm -r /lib/modules/$(uname -r)/updates/rtw89 /etc/modprobe.d/rtw89-frame.conf
sudo depmod -a
Then reboot.
Data point on the side note above about the native Half-Life: Alyx serializedentity.h (797) / GetBitRange() assertion: I hit the exact same assertion with the game installed on btrfs, not NTFS, so the filesystem doesn't seem to be the trigger.
It reproduces deterministically for me during the train ride on a2_pistol, from the same autosave, failing on the identical offset both times (GetBitRange( 6661 -> 6661 )). That session also showed this issue's reset storm and the videovulkan.cpp:1641 assert during the level load, but the game crash came about a minute later and looks game-side rather than vrlink-side.
Since it's a separate bug, I filed it as #986 with stacks, console excerpts and a Steam crash ID (RTX 4080, NVIDIA 610.57.04, SteamVR 2.18.2 beta, Steam Frame).
Follow-up to my earlier report: the reset storms still reproduce on SteamVR 2.18.2 beta (Fedora 44, AMD APU / RADV, FCC regdomain). The workaround that made Half-Life: Alyx playable here is @Molier's TX power patch plus @RalfN's low latency script.
Before: ~270 resets/min, 19% dropped frames, unplayable.
After: ~17–22 resets/min, ~2.5% dropped frames, playable with brief interruptions.
What low latency mode is: on SteamOS, Steam switches the adapter into a low latency mode on connect through a helper that desktop distros don't ship (holo-realtek-firmware-toggles set-low-latency-mode on, source in holo-main). On other distros it comes down to this, as root, once the headset is connected ($IF is the adapter interface, $D its /sys/kernel/debug/ieee80211/phyN/rtw89):
iw dev $IF set power_save off; iw dev $IF set tidconf tids 0xff amsdu off
for r in c300 c304 c308 c30c; do echo "$r 003F3219 4" > $D/write_reg; done # EDCA: TXOP 2000us, CWmax 7, CWmin 3, AIFSN 1
echo 0x30 > $D/disable_dm # firmware scan + inactive power save off; write 0 back on disconnect, or the adapter can't scan to reconnect
Fedora: the stock kernel lacks rtw89 debugfs, so the rtw89 modules must be rebuilt before write_reg and disable_dm exist. Build flags below.
Summary of findings: the beta alone did not fix it. The TX power patch cut dropped frames from 28% to 4.9%, and the low latency script brought resets down to ~20/min. Multi-link made no clear difference either way. Two to three short bursts per minute remain even with both applied, and storms also occur over home Wi-Fi with the adapter out of the path.
Correction to my earlier comment: I cited "0 tx retries, 0 tx failed" as evidence of a healthy link. As @Molier pointed out, those counters aren't implemented for this USB driver, so that claim should be disregarded. They read 0/0 in every run below, including the worst.
System (unchanged except versions): AMD Radeon 8060S (Strix Halo APU), RADV / Mesa 26.2.3 freeworld, Fedora 44 KDE Wayland, kernel 7.2.8-200.fc44, SteamVR 2.18.2 beta (v1790893534), Steam client 1788652215. Steam Frame Wireless Adapter on rtw89_8852cu, USB 3 at 5000M behind two hubs, 6 GHz ch 37, regdomain US. Half-Life: Alyx native, 50% render resolution. The PC's onboard Wi-Fi (5 GHz, 40 MHz) is its only home network connection.
Each run keeps everything from the row above it and adds one change. Counts are over the window where hlvr was running; dropped frames are from the compositor's Total ... presents / dropped line.
| Configuration | Play time | Resets/min | Bursts/min | Longest burst | Dropped frames | Adapter PHY tx rate (mean) |
|---|---|---|---|---|---|---|
| Beta defaults (multi-link on, power save on) | 2.6 min | 268 | 9.1 | 9.7 s | 19.3% | 567 Mbit/s |
+ allowMultipleLinks false |
3.2 min | 335 | 8.5 | 9.7 s | 20.7% | 622 |
+ forceBaselineVideoFEC true |
2.9 min | 92 | 5.5 | 43.8 s | 28.0% | 588 |
+ reg6_pwr_override=2 (LPI) |
3.3 min | 117 | 5.8 | 4.6 s | 4.9% | 854 |
| + low latency script (also turns power save off) | 7.2 min | 22 | 2.1 | 6.2 s | 2.5% | 903 |
| same, multi-link back on | 14.6 min | 17 | 2.9 | 4.7 s | 2.6% | 957 |
A "burst" is a run of Reset video stream because we had a stream reset request lines with no gap over 2 s.
What I take from it:
Caveats: one run per configuration, most of them short; the changes are stacked, not isolated; Alyx has no chapter select, so the runs were not on an identical segment; the low latency row changes power save and the EDCA/firmware settings together.
In one run with allowMultipleLinks false, vrlink logged Found primary link <home Wi-Fi address> two seconds before the adapter finished associating, and then stayed on home Wi-Fi for the whole session; the adapter carried nothing. Over 4.7 min at ~60 Mbit/s on 5 GHz: 24 resets/min, 4.3 bursts/min, 5.2% dropped. So the storms occur with the adapter out of the path, as others have reported.
This is also a small trap for anyone testing single-link: start SteamVR, wait for the adapter to associate, and only then start the stream, or you may be measuring your home network.
The three lines above are what @RalfN's script (posted earlier in this thread) applies in a loop. Three things from running it here:
disable_dm 0x30 set, the driver rejects every scan (-EBUSY), so the flag has to be cleared while the adapter is disconnected. I made the loop write 0 to disable_dm whenever iw dev $IF link is not Connected; replugging the adapter also clears it.reset writes 0x00 to disable_dm, which is the same clearing step as above.CONFIG_RTW89_DEBUGFS unset (same as Bazzite, per @Lewin225), so neither txpwr_table nor the low latency settings are available on the stock driver. I rebuilt the rtw89 modules from vanilla 7.2.8 source against kernel-devel, adding CONFIG_RTW89_DEBUG=y CONFIG_RTW89_DEBUGFS=y CFLAGS_MODULE="-DCONFIG_RTW89_DEBUG=1 -DCONFIG_RTW89_DEBUGFS=1" to the make line from @nix70900-bit's guide. The modules loaded against the Fedora kernel without complaint, and modprobe -r / modprobe picked them up without a reboot.OpenSSL EVP (New) AES PERF: ~950–1400 MByte/s).Adding my voice to the two requests already made: apply the low-latency adapter settings on desktop Linux as on SteamOS and Windows, and the remaining bursts still look like vrlink turning short stalls into reset storms. Full vrserver.txt / vrcompositor.txt and per-second link captures for every run above are available on request.
I moved to the patched in-tree rtw89 driver with @Molier's patch, in order to weed out any other influencing factors and upgraded to linux kernel 7.3-rc2, which resulted in the same amount of stream resets as with my previous setup.
The biggest change came from the low-latency script, which significantly improved my experience and made Half-Life Alyx actually playable, with stutters only happening only happening at most once a minute or so (although this also might be because I am in the quarantine zone now, which has small enclosed spaces).
So as a quick recap:
Starting point: HLA unplayable, dangerous to even walk with how often the stutters happen.
TX power patch: HLA still stutters, but less frequently, indoor scenes are somewhat playable.
Low-latency script: Best experience yet, still some stutters but not at a point where I would prefer the standalone version anymore, simply because the visual upgrade is worth it.
System:
(as an aside, normally I run steam-native, as otherwise the steam overlay does not work. However SteamVr fails with -201 (unable to start vrcompositor) on steam-native)
Additional reproduction on a different AMD/Bazzite system:
amdgpu), Mesa 26.2.4rtw89_8852cu, USB 3I get the same periodic video freezes/audio interruptions through both the Frame adapter and ordinary home Wi-Fi, so this does not appear specific to the adapter or rtw89.
During one ~2m20 affected stream, vrserver.txt recorded 158 Reset video stream because messages and 96 SVLFEC::ReportStreamReset() calls. I did not see the ulVideoTimeline == ulTimelineSequence assertion in this particular capture.
I can provide the complete logs/system report if useful.
I had the same issue, but reducing SteamVR's resolution per eye from 200% to 150% fixed it (still have one dropped frame every 30 or so seconds but not the big stutters).
Steaming from wifi, dongle is unplugged.
OS: Debian 12 Linux
GPU: NVIDIA RTX 4090
SteamVR: Beta 2.18.2
Headset: Steam Frame, wireless streaming
Refresh rate: 90 Hz
Setup: Nobara 44 (CachyOS-based kernel 7.2.9-200.nobara.fc44), i9-10850K, RTX 4070 SUPER (NVIDIA 595.104.02), KDE Plasma Wayland, regdomain DE, SteamVR beta (build 25839986), Steam Frame Wireless Adapter (28de:2432, in-tree rtw89_8852cu) on USB 3, 6 GHz ch 37 / 160 MHz.
Host Reset video stream per minute in HL:Alyx:
| Configuration | Resets/min |
|---|---|
| stock | ~84 |
| + @RalfN's low latency script | ~36 (bursts start after a few minutes) |
+ @Molier's reg6_pwr_override=2 (LPI confirmed in dmesg) |
~9 over 14 min, mostly in 2 short bursts, many minutes with 0 |
With LPI the TX bitrate went from 650–860 Mbit/s (HE-MCS 5) to 1.3–2.4 Gbit/s (HE-MCS 7–11). Audio still stutters a bit while streaming.
Two pitfalls I hit, in case they help others:
disable_dm 0x30 (HW_SCAN off) breaks reconnecting. After the headset disconnected once, the adapter couldn't find the Frame AP again (NetworkManager activation failed with "network not found", the scan showed the SSID with channel 0 / signal 0). My version of the script writes 0 to disable_dm whenever there's no station, and sets it again after association. Reconnects work fine since.PAD_CTRL2 (MATCH_CNT) and skips the switch. Unplugging and replugging once brings it back to 5000M. Worth checking lsusb -t if your results look worse than expected.Also, iw dev <if> link sometimes reported "Not connected" while the stream was running; iw dev <if> station dump was reliable for the connection check.
#!/bin/bash
# Low latency mode for the Steam Frame Wireless Adapter (28de:2432), modelled on SteamOS'
# holo-realtek-firmware-toggles (based on @RalfN's script in [#965](/issue/ValveSoftware/SteamVR-for-Linux/965)).
# Re-checks every 5 s because the EDCA registers get reset on stream restarts.
# Left out on purpose: static -75 dBm PD threshold and HE-MCS cap (issues reported in this thread).
edca="003f3219" # TXOP 2000 us, CWmax 7, CWmin 3, AIFSN 1
while sleep 5; do
iface=""
for dev in /sys/class/net/*; do
if [[ $(cat "$dev/device/../idVendor" 2>/dev/null) == 28de &&
$(cat "$dev/device/../idProduct" 2>/dev/null) == 2432 ]]; then
iface=$(basename "$dev")
break
fi
done
[[ -n $iface ]] || continue
d="/sys/kernel/debug/ieee80211/$(basename "$(readlink -f "/sys/class/net/$iface/phy80211")")/rtw89"
[[ -d $d ]] || { echo "no rtw89 debugfs at $d"; continue; }
# Not connected: re-enable firmware HW_SCAN. With HW_SCAN disabled the adapter
# can't find the Frame on 6 GHz again after a disconnect (scan shows channel 0, signal 0).
# 'iw link' sometimes says "Not connected" during a stream, so use station dump instead.
if ! iw dev "$iface" station dump 2>/dev/null | grep -q '^Station'; then
if ! grep -q 'Disabled DM: 0x0$' "$d/disable_dm"; then
echo 0 > "$d/disable_dm"
echo "not connected: re-enabled HW_SCAN on $iface"
fi
continue
fi
grep -q 'at 0x0000c300=' "$d/read_reg" || echo "c300 4" > "$d/read_reg"
[[ $(grep -o '0x[0-9a-f]*$' "$d/read_reg") == "0x$edca" ]] && continue
echo 0x30 > "$d/disable_dm" # firmware HW_SCAN + INACTIVE_PS off
iw dev "$iface" set power_save off
iw dev "$iface" set tidconf tids 0xff amsdu off
for r in c300 c304 c308 c30c; do echo "$r $edca 4" > "$d/write_reg"; done
echo "applied low latency mode on $iface"
done
Transparency note: I worked through the diagnosis, the driver build and this script together with Claude (Anthropic's AI assistant). The measurements are from my own sessions.
System:
Symptom: identical to the original report — the stream freezes for ~1–2 seconds while the game keeps
running on the PC (headset and inputs still tracked), audio crackles, then the stream re-establishes.
Occurs every few minutes during normal play (ITR1).
Already applied, no improvement of the resets:
Log evidence (vrserver.txt):
$ grep -c "Reset video stream" ~/.local/share/Steam/logs/vrserver.txt
1448
$ grep -m3 "ulVideoTimeline" ~/.local/share/Steam/logs/vrserver.txt
Sat Oct 10 2026 18:22:16.688272 [Info] - vrlink: ASSERT: "pFrame->ulVideoTimeline == ulTimelineSequence" at /data/src/vrlink/driver_vrlink/videovulkan.cpp:1685.
Sat Oct 10 2026 18:32:05.518147 [Info] - vrlink: ASSERT: "pFrame->ulVideoTimeline == ulTimelineSequence" at /data/src/vrlink/driver_vrlink/videovulkan.cpp:1685.
Update to my last comment, from testing today:
iw dev <if> station dump while playing and try to keep the signal better than −55 dBm. Moving my adapter from the desk beside the PC to hanging over a door frame, elevated and in clear line of sight, took Half-Life: Alyx from ~80 resets/min to 2.7, with the other workarounds unchanged.patch -l and no manual placement. Rebuild after every kernel update, or you are silently back on the stock driver.Same settings in both runs, 25 minutes apart: @Molier's reg6_pwr_override=2, @RalfN's low latency script, forceBaselineVideoFEC, multi-link on, Fedora 44, kernel 7.2.9, SteamVR beta v1791582248.
| Adapter position | Play time | Resets/min | Largest burst | Dropped frames | Signal (median) | Adapter PHY tx rate (mean) |
|---|---|---|---|---|---|---|
| On the desk beside the PC, via a USB 3 hub | 12.0 min | ~80 | 307 resets | 5.6% | −60 dBm | 884 Mbit/s |
| Over a door frame, on a USB 3 extension cable | 14.1 min | 2.7 | 14 resets | 0.75% | −48 dBm | 1703 Mbit/s |
Kernel 7.2.9: the patch applies to vanilla 7.2.9 regd.c, builds against Fedora's kernel-devel with the debugfs flags from my earlier comment, and logs 6 GHz power class forced to 1 by reg6_pwr_override. Modules installed under updates/ are per kernel: after the update to 7.2.9 I had no LPI and no debugfs for the low latency script until I rebuilt. A quick check is whether /sys/module/rtw89_core/parameters/reg6_pwr_override exists.
Correction: I wrote that I had not seen the EDCA registers get cleared mid-session. Today they were cleared once while the adapter stayed associated, and the script rewrote them at its next 5 s check, as @RalfN described.
Still open: in the good run the stream stopped once for about 10 s at −46 to −59 dBm, on both links at the same moment, with no reset requests beforehand. vrlink logged Connection inactive, the headset showed a "waiting" popup, and it recovered by itself. That looks like a separate problem from the reset storms.
Captures and logs for both runs are available on request.
I reverse engineered some parts of vrlink to try to figure this out and there's some oddities in the logic.
Basically vrlink uses a UDP based protocol to transmit frames to the headset. As part of this protocol, each frame gets a number, and the headset sends acknowledgements with the number of the last frame it decoded (4 times per frame interval). This tracks where the headset is in relation to the transmission of frames. The host uses the difference between the current acknowledged frame number and the number of the next frame it plans to transmit to perform flow control. This seems to be used both to prevent the host from running too far ahead of the headset but also to implement bandwidth limits (target bandwidth).
Side note: Frames aren't sent as single packets, but are fragmented and then re-assembled, this means that one lost fragment can cause things to get stuck on that frame.
If the difference between the next frame number and the last acknowledged frame exceeds 6, the host forces frame rendering to slow down to 3.3FPS until that number falls below 6 (so in reality it doesn't actually start rendering at 3.3FPS, because this delta is re-checked at the target framerate).
Side note: For the purpose of this calculation, the "last acknowledgement number" can go down as well as up. If an old frame ends up arriving late and getting acknowledged after it was already re-requested (the headset can re-request frames) then that old acknowledgement number can temporarily bump the value above 6 when everything is going fine. This is okay as, unless the headset had caught up with all acknowledgements, the next actual frame would fix this and nothing would really break (probably). But it's something that can and should probably be fixed. The counter is 16 bits and wraps around, but it's not hard to impose a window for valid acknowledgements and keep the "last acknowledgement number" as a "maximum" modulo 2^16.
The problem occurs when the headset requests a stream reset. In my case, the headset logs: "Received frame outside of backtrack window. Resetting." This is logged when the headset finishes reassembling a frame which is more than 5 frames ahead of the last successfully decoded frame. This can happen when a prior frame (to the one which was just finished being reassembled) has a lost fragment which was never received. It stalls decoding (the headset does re-request missing fragments at various points in time, so it's not too easy to hit this, but given the amount of data/frames involved, even rare events can happen often enough to cause issues).
When the host receives a reset request, it clears its frame transmit queue, clears the "last acknowledgement number" to -1, and pends an encoder reset. When the next frame window arrives and SubmitFrame is called (name comes from a tracing label, it's in driver_vrlink.so) is called, it sees the pending encoder reset, and cleans up some state including the encoder state and submits a frame to be rendered (and encoded and sent). Resetting the encoder state means that the next frame will be (effectively) a keyframe and won't depend on any prior frames.
The problem is that by the time the headset requests a reset for the reason outlined above, the delta between the "last acknowledgement number" and "next frame number" is at least 6, in practice there's a good chance it's at least 7 since the host has likely started sending the next frame by the time the headset finished receiving the one that triggered the issue. Moreover, the headset continues sending acknowledgements at a rate of 4 per frame even after requesting a reset. The host doesn't ignore acknowledgements received between receiving a reset request and sending its first subsequent frame. You can hopefully see where this is going.
In summary, the sequence of events is:
If your 6GHz band is currently having a moment of weakness, your framerate basically goes down to 3.3FPS or worse.
I patched my driver_vrlink.so so that it lets PostPresent call SubmitFrame regardless of the gap when a reset is pending. And this has improved things pretty massively. You can download it here. It's in the form of a BPS, look for "BPS patcher" and you'll find tools which can apply this to Steam/steamapps/common/SteamVR/drivers/vrlink/bin/linux64/driver_vrlink.so.
I am not satisfied with this patch, as it still leaves the throttle running until the headset receives the first frame... I'm going to improve it unless valve beats me to it.
There are other bugs in there, one that causes ASSERT: "pFrame->ulVideoTimeline == ulTimelineSequence" which is caused by a race in the encoder reset code (here's a combined BPS). And there are bugs on the headset side. After issuing a reset, the headset clears the frames it has fully received, but leaves their completed state set which signals they've been completely received this can lead to the decoder being asked to decode nothing if the frame which caused a reset, although I don't think this would cause any visible problem.
The bigger bug is that the frame's video decoder gets reset when the frame requests a stream reset, and this can cause the VIDIOC_DQBUF ioctl call to return EAGAIN after polling ready, presumably because the reset happened in between the poll and the ioctl. This causes the decoder worker to exit, and this can take up to 800ms for the decoder worker to get restarted. This can cause a sequence of stream resets because the decoder is stuck and so the headset keeps hitting the limit of receiving a frame more than 5 ahead of the last decoded one. The watchdog that restarts the decoder itself requests stream resets. So I think this explains the reset storm issue. But I haven't yet gotten around to putting together a patch for this.
I optimistically suspect that with these frame-side bugs fixed, and the host-side bugs fixed, this issue could itself be closed.
This entire thread is a gold mine of analysis and solutions. Is anyone making sure anyone at Valve actually sees it?
proton experimentalx3 2026-10PIPEWIRE_LATENCY=2048/48000 %command%x2 2026-09
Describe the bug
Steam Frame streaming over the included wireless adapter freezes for ~1–2 seconds roughly every 20–60 seconds, with audio crackling at the same time. At each freeze, the headset stops acknowledging frames and requests stream resets in rapid succession, and vrlink hits an assertion in the Vulkan video encoder:
In a ~3 minute session on the SteamVR beta: 154 "Reset video stream" lines and 5 occurrences of the assertion.
The wireless link does not appear to be the cause:
iw station dumpshows 0 tx retries and 0 tx failed during the whole session, including during the freezes (the counters do work: a couple of failures were recorded after the session ended)iw eventshows no scans, disconnects or channel switches during the freezesTo Reproduce
vrserver_redacted.txtfor bursts of "Reset video stream" and thevideovulkan.cpp:1643assertion.Expected behavior
Smooth streaming without periodic freezes, as on Windows with the exact same hardware and settings. There's no issue on Windows.
System Information (please complete the following information):
rtw89_8852cudriver, USB 3 (5000M)Screenshots
N/A
Additional context
Tested on the same PC via dual-boot Windows, same GPU, headset, adapter and settings: no freezes, no audio crackling, smooth streaming. This points to the Linux vrlink Vulkan encode path on NVIDIA.
Logs
vrserver_redacted.txt