protonscr

Warhammer 40,000: Space Marine 2

protonopen appid 2183900Game compatibility - UnofficialoverlayXAudio2
ValveSoftware/Proton#8072 · opened 2024-09-05 by zr00da · updated 2026-10-12 · 224 comments · github · game page · search this game
Zzr00da 2024-09-05 github

Compatibility Report

  • Name of the game with compatibility issues: Warhammer 40,000: Space Marine 2
  • Steam AppID of the game: 2183900

System Information

I confirm:

  • [x] that I haven't found an existing compatibility report for this game.
  • [x] that I have checked whether there are updates for my system available.

steam-2183900.zip

Symptoms

Game launches fine. When new game is started and the intro cinematic runs (which seems to double as map loading), a message pops up saying "You have failed to connect to the game" in always the same spot. After confirming the popup the game displays a black window with a "Signed in as [USER]" message in left top corner and doesn't respond anymore.

Possibly anti-cheat related? Running SteamDeck=1 doesn't help.

Reproduction

Start new game, watch intro cinematic, always get disconnected.

Ddennis1248 2024-09-05 github

For me usually on the 2nd try of starting a new game it does not disconnect.

The main issue I run in to is that the game gets stuck on the loading screen when resuming the campaign. It runs fine until I quit the game, after which I become unable to resume the campaign. I can however still start a new game.

steam-2183900.log

Update: I think I found a workaround, disabling internet seems to allow me to launch a solo game.

The game also crashes any time I receive a Steam achievement.

Update 2: Actually, maybe the disabling internet trick does not work, and I just got lucky a few times.

Update 3: Disabling the Steam overlay solves the crashing issue. I managed to do a full playthrough with this workaround. Game may still crash on shutdown but otherwise works fine.

Aalosarjos 2024-09-05 github

Just to be sure, you have the Proton EasyAntiCheat runtime installed, right?

Zzr00da 2024-09-05 github

Just to be sure, you have the Proton EasyAntiCheat runtime installed, right?

Sure, the install script will add it either way if you don't (my mistake this is false, the runtime isn't automatically installed). FWIW I can run other EAC games fine - Elden Ring and Hunt: Showdown from what I have installed atm. I guess I can try reinstalling the whole thing. You can run the game I presume?

For me usually on the 2nd try of starting a new game it does not disconnect.

Interesting. I'm getting 100% failure rate, always in the same spot when the camera shows the green goo cannister. Tried with various Proton versions probably 20 times.

Zzr00da 2024-09-06 github

I've cleaned the prefix and reinstalled EAC runtime but unfortunately the "Failed to connect" problem persists 😢
The install script for the game seems to correctly set up both EAC and EOS as far as file structure, although I couldn't find any specific logs from the process. FWIW I've also connected the game to the PROS account, seems that can't be easily disconnected again - might or might not be related.

At this point I'm out of ideas, hopefully someone chimes in. The perks of early access on Linux 😄

Aalosarjos 2024-09-06 github

Replying to https://github.com/ValveSoftware/Proton/issues/8072#issuecomment-2332663938

I was looking into getting regular version but it looks like the game devs didn't put on the game page that it uses Epic Online Service (Lots of bad reviews because of that) so maybe Steam wouldn't install it automatically, but if you are playing Hunt, you should have installed.

Bbenbot 2024-09-06 github

So for me using GE-proton 9-4 and turning cross play off under Game settings seems to make everything work fine.

started a new game and saw no disconnect message

Zzr00da 2024-09-06 github

Disabling Steam Overlay works! 🥳

(Settings > In Game > uncheck Enable Steam Overlay while in-game)

Aalosarjos 2024-09-12 github

Finally could give it a try, and as the others, needed to disable Steam Overlay to make it work (Suck, because this games deserves getting some screenshots...) and crashing when closing it, have to stop it from the Steam client

BBillli11 2024-09-13 github

This game seem to also affected by https://github.com/HansKristian-Work/vkd3d-proton/issues/1406.
launching the game with VKD3D_CONFIG=no_upload_hvv %command% have ~20% fps improvement for me.

Aalosarjos 2024-09-13 github

Can confirm a performance improvements with that flag! :D

EEliasDadde 2024-09-13 github

Can confirm a performance improvements with that flag! :D

didn't work here, on windows the difference is 30% , but i think the issue is the nvidia linux driver and directx 12 , not really related to proton.

Nneon-grim 2024-09-13 github

I've encountered another issue with space marine 2. For some reason when certain light sources are present on screen, weird green and red artifacts can be spotted on the edge of the screen when moving the camera. Here is a video displaying the issue.

My specs:

  • OS: Nixos unstable branch
  • Kernel: 6.10.9 default
  • Mesa: 24.2.2
  • Compositor: Hyprland v0.42
  • GPU: Sapphire 7900XTX pulse
  • CPU: 7800X3D
  • RAM: 2x16GB 6000Mhz CL 30
NNiedzwiedzw 2024-09-13 github
  • OS: NixOS 24.05.20240907.68e7dce (Uakari) x86_64
  • Host: ASUSTeK COMPUTER INC. TUF GAMING X570-PLUS (WI-FI)
  • Kernel: 6.6.49
  • Uptime: 2 hours, 7 mins
  • Packages: 1466 (nix-system), 1379 (nix-user)
  • Shell: bash 5.2.32
  • Resolution: 1920x1080, 2560x1440, 1920x1080
  • WM: sway
  • Terminal: WezTerm
  • CPU: AMD Ryzen 9 3900X (24) @ 4.000GHz
  • GPU: AMD ATI Radeon RX 7900 XT/7900 XTX/7900M
  • Memory: 10634MiB / 128724MiB
  • ✦ ❯ glxinfo | grep "OpenGL version" prints "OpenGL version string: 4.6 (Compatibility Profile) Mesa 24.0.7"

the game launches but once the cutscenes stop and I'm about to be handed control over character the game freezes with weird graphical artifacts
image

NNiedzwiedzw 2024-09-13 github

Replying to https://github.com/ValveSoftware/Proton/issues/8072#issuecomment-2349260726

looks like we have similar GPU + nixos, might that be some configuration problem with nixos?

Aalosarjos 2024-09-13 github

Haven't seen any weird artifacts on the prologue and first level on:

7800X3D + 7800XT
Arch + Gnome + Mesa 24.2.2

Or at least didn't notice, but I see the last messages are all about artifacts and using Nixos, maybe something related to how mesa is build there? Are you using Proton Experimental?

NNiedzwiedzw 2024-09-13 github

Replying to https://github.com/ValveSoftware/Proton/issues/8072#issuecomment-2350138190

yeah it's proton experinental. tbh its a pretty fresh install, im still trying to figure out how it's configured, i might be missing something

NNiedzwiedzw 2024-09-14 github

✦ ❯ glxinfo | grep "OpenGL version"
OpenGL version string: 4.6 (Compatibility Profile) Mesa 24.0.7

Aalosarjos 2024-09-14 github

✦ ❯ glxinfo | grep "OpenGL version" OpenGL version string: 4.6 (Compatibility Profile) Mesa 24.0.7

That's kinda outdated mesa

Nneon-grim 2024-09-15 github

Replying to [#8072 (comment)](https://github.com/ValveSoftware/Proton/issues/8072#issuecomment-2349260726)

looks like we have similar GPU + nixos, might that be some configuration problem with nixos?

Cant say, I havent changed anything bout my mesa config. This would be my config.

Nneon-grim 2024-09-15 github

Haven't seen any weird artifacts on the prologue and first level on:

7800X3D + 7800XT Arch + Gnome + Mesa 24.2.2

Or at least didn't notice, but I see the last messages are all about artifacts and using Nixos, maybe something related to how mesa is build there? Are you using Proton Experimental?

I mainly see the artifacts when moving the camera, I thought maybe my GPU might be dying, but I experience no such artifacts in other heavy games. They only appear during fast mouse movement and only in indoor areas where warm light sources are present.

Aalosarjos 2024-09-15 github

Haven't seen any weird artifacts on the prologue and first level on:
7800X3D + 7800XT Arch + Gnome + Mesa 24.2.2
Or at least didn't notice, but I see the last messages are all about artifacts and using Nixos, maybe something related to how mesa is build there? Are you using Proton Experimental?

I mainly see the artifacts when moving the camera, I thought maybe my GPU might be dying, but I experience no such artifacts in other heavy games. They only appear during fast mouse movement and only in indoor areas where warm light sources are present.

Have no idea of Nix, you sure you using RADV and not AMDVLK right? I saw the env var to be setted correctly, but also AMDVLK installed?

Nneon-grim 2024-09-15 github

Reply to https://github.com/ValveSoftware/Proton/issues/8072#issuecomment-2351557454

AMDVLK is currently disabled on my system, games are running through mesa/RADV.

Kkadosch 2024-09-16 github

Replying to https://github.com/ValveSoftware/Proton/issues/8072#issuecomment-2350082785

Got the exact same issue:
OS: Arch Linux
Host: ASUSTeK COMPUTER INC. ROG STRIX B650E-I GAMING WIFI
Kernel: 6.10.10-1-cachyos
Mesa: 24.2.2
Resolution: 2560x1440
WM: KWin
CPU: AMD Ryzen 7 7800X3D
GPU: AMD ATI Radeon RX 7900 XT/7900 XTX/7900M
Memory: 12176MiB / 64015MiB

For the moment got it to work switching to AMDVLK instead of RADV.

Uurbenlegend 2024-09-18 github

This game seem to also affected by HansKristian-Work/vkd3d-proton#1406. launching the game with VKD3D_CONFIG=no_upload_hvv %command% have ~20% fps improvement for me.

Adding that flag has no affect for me on my Nvidia 3090 with Proton Experimental.

I am also getting a long hang and then crash whenever I quit the game. Most of the time I get this dialog message.
Screenshot_20240918_002854

Other times I get the crash reporter.

Aalosarjos 2024-09-18 github

Replying to https://github.com/ValveSoftware/Proton/issues/8072#issuecomment-2357723450

To me on AMD game always crashes on exiting, have to stop it from the steam client. That flag helped me somehow for the game to make better usage of my CPU and GPU, if you were already CPU bounded it probably won't do anything.

I finished the campaign, what a bummer not to have the Steam Overlay, I would just non-stop make screenshots of it

BBillli11 2024-09-18 github

To me on AMD game always crashes on exiting, have to stop it from the steam client. That flag helped me somehow for the game to make better usage of my CPU and GPU, if you were already CPU bounded it probably won't do anything.

The flag is for CPU bound. It trade gpu performance with cpu performance for some game, and it is for disabling rebar in vkd3d.

Check the issue https://github.com/HansKristian-Work/vkd3d-proton/issues/1406 for more information.

Xx5f3759df 2024-09-26 github

After 3.0 patch game doesn't playable in online mode. Looks like EGS services do not work anymore.

Online doesn't work on Proton 9.0-3 or Experimental or latest Proton-GE

image

Aalosarjos 2024-09-26 github

After 3.0 patch game doesn't playable in online mode. Looks like EGS services do not work anymore.

Online doesn't work on Proton 9.0-3 or Experimental or latest Proton-GE

image

Not sure if because of not connection to EGS at all or if something fixed on the update, but the game is exiting fine now at least...

LLazyWings 2024-09-26 github

After 3.0 patch game doesn't playable in online mode. Looks like EGS services do not work anymore.

Online doesn't work on Proton 9.0-3 or Experimental or latest Proton-GE

image

Sigh.... Here they go again. It's really frustrating honestly. I was so excited for the new patch.

Steps I've taken:

  • Proton Experimental, 9.0-3, GE 9-13. Will test bleeding edge and GE 9-14. Edit: GE 9-14, Experimental bleeding edge and Hotfix have same result. First launch after a prefix change results in immediate crash, second launch goes to menu fine. All testing with Steam Overlay disabled since that's the only way the game would work before.
  • Verifying integrity (EAC file updated)
  • Run through gamescope (same issue)
  • Disabled crossplay from in game menu (initially the option was greyed out, then I managed to change it but it wasn't clear whether it had an effect)
  • Linked Epic Games Account in game (recognised my account and enabled the Epic overlay but did not affect ability to connect to online server)

Running OpenSUSE Tumbleweed, everything up to date.

BBillli11 2024-09-26 github

Look like AVF error is not linux only problem.
There are few message said they have this error on windows example.

Most seem to be on linux/steam deck though.

Xx5f3759df 2024-09-26 github

Looks like everything that using online features doesn't work. Even PROS account. EGS account doesn't work too. PROTON_LOG=1 says nothing. Maybe there is another way to get some information.

Aalosarjos 2024-09-26 github

I'm not sure if this is a good moment to get more info on the Steam Interface with the game, now the game can boot with the interface enabled, but it will just freeze when trying to open it

Jjjones0293 2024-09-28 github

There's a bug report on their forum for the AVF error. Please upvote/comment if you're experiencing the same issue

https://community.focus-entmt.com/focus-entertainment/space-marine-2/bugs/2517-connection-error-error-code-avf?page=1

Zzaggynl 2024-10-03 github

Am also getting the AVF error, unable to use online play.
proton log: steam-2183900.log
sysinfo: https://gist.github.com/zaggynl/4d4649e98bcf1cf7b32a4945d6dec148

Ddubiousgit 2024-10-04 github

Update:

The response from the developer in the next message addresses the issues originally raised in this post now.

BBillli11 2024-10-04 github

Dev just posted a announcement on discord that the issue linux/steam deck will be fixed next patch.

Regarding the black screen issue occurring on Oceania servers:

We are aware of it, the dev teams are on the matter at the moment.
We'll let you know when we get a fix.

For the Linux/Steam Deck issue:

The next patch should fix the launch issue on Linux and Steam Deck.

<@&1242516345237798942>

Discord link
a

Aalosarjos 2024-10-04 github
BBillli11 2024-10-04 github

@alosarjos Nope, just this.
No date yet.

BBillli11 2024-10-08 github

Hotfix 3.1 is released.steam link.

Space Marine 2 - Hotfix 3.1
Hello Space Marines!

We just pushed a small hotfix that brings various fixes. Thank you for your support!

Patch Notes

Fixed several crashes
Fixed heavy stutters on some CPUs
Fixed launch issue on Linux and Steam Deck
Fixed issue with dynamic resolution and ultrawide screens
Fixed issue with upscalers using wrong resolution parameters

a

Edit: Still getting AVF error. verifying game files.

Edit 2: Still getting AVF.
a

Edit 3:Adding env SteamDeck=1 seem to fix the online issue.From steam discussion

LLazyWings 2024-10-08 github

Yeah I just tried booting up in my lunch break. It works with the SteamDeck=1 variable. I can also run it alongside in gamescope by putting the variable in first. My env is SteamDeck=1 gamescope -h 1440 -r 165 --force-grab-cursor -- %command%

It's not the greatest fix, but it works I guess.

Edit: Note that the variable also sets all your in game settings to those optimised for the Steam Deck. If you were running on high graphics settings, they'll be turned down very low. I also don't know about people using Nvidia systems. There may be issues with DLSS, but I can't test this because I have an AMD GPU.

Ssigzegv 2024-10-08 github

Works for me, and as previously said graphics are effectively nerfed...

Uurbenlegend 2024-10-08 github

Edit: Note that the variable also sets all your in game settings to those optimised for the Steam Deck. If you were running on high graphics settings, they'll be turned down very low. I also don't know about people using Nvidia systems. There may be issues with DLSS, but I can't test this because I have an AMD GPU.

DLSS works fine and AFAICT setting graphics settings back to ultra works, but will shoot out a warning about VRAM when doing so.

Oo-bri 2024-10-10 github

EDIT: It seems to be a Manjaro Problem: https://forum.manjaro.org/t/steam-games-wont-launch-after-2024-10-10-stable-update/169230
If someone has a solution, I will be happy anyways.

Unfortunality, the game does not work for me.

I only get a black screen and the game seems then to block my hole PC.
When I use gamescope with: SteamDeck=1 gamescope -h 1440 -r 165 --force-grab-cursor -- %command% as suggested by @LazyWings the game also just produces a black screen, but at least I can use my computer after the failed start attamped without rebooting.

I tried so far:

  • Proton Experimental
  • Proton 9.03
  • Proton GE 9-15
  • All with and without SteamDeck=1 %command
My specs:
Computerinformationen:
Hersteller: Micro-Star International Co., Ltd.
Modell: X570-A PRO (MS-7C37)
Formfaktor: Desktop
Touch-Eingabe nicht erkannt
Prozessorinformationen:
CPU-Hersteller: AuthenticAMD
CPU-Marke: AMD Ryzen 7 5800X 8-Core Processor
CPU-Familie: 0x19
CPU-Modell: 0x21
CPU-Stepping: 0x2
CPU-Typ: 0x0
Geschwindigkeit: 4851 MHz
16 logische Prozessoren
8 physische Prozessoren
Hyper-Threading: Unterstützt
FCMOV: Unterstützt
SSE2: Unterstützt
SSE3: Unterstützt
SSSE3: Unterstützt
SSE4a: Unterstützt
SSE41: Unterstützt
SSE42: Unterstützt
AES: Unterstützt
AVX: Unterstützt
AVX2: Unterstützt
AVX512F: Nicht unterstützt
AVX512PF: Nicht unterstützt
AVX512ER: Nicht unterstützt
AVX512CD: Nicht unterstützt
AVX512VNNI: Nicht unterstützt
SHA: Unterstützt
CMPXCHG16B: Unterstützt
LAHF/SAHF: Unterstützt
PrefetchW: Nicht unterstützt
Betriebssystem:
"Manjaro Linux" (64 Bit)
Kernel-Name: Linux
Kernel-Version: 6.11.2-4-MANJARO
X-Server-Anbieter: The X.Org Foundation
X-Server-Release: 12101013
X-Fenstermanager: KWin
Steam-Laufzeitversion: steam-runtime_0.20240806.97925
Grafikkarte:
Treiber: AMD AMD Radeon RX 6800 XT (radeonsi, navi21, LLVM 18.1.8, DRM 3.59, 6.11.2-4-MANJARO)
Treiberversion: 4.6 (Compatibility Profile) Mesa 24.2.4-arch1.0.1
OpenGL-Version: 4.6
Desktopfarbtiefe: 24 Bit per Pixel
Monitor-Bildwiederholfrequenz: 165 Hz
Anbieterkennung: 0x1002
Gerätekennung: 0x73bf
Revision nicht gefunden
Anzahl Monitore: 1
Anzahl logische Grafikkarten: 1
Prim. Anzeigeauflösung: 2560 x 1440
Desktopauflösung: 2560 x 1440
Primäre Anzeigegröße: 27.44" x 15.43" (31.46" diag), 69.7cm x 39.2cm (79.9cm diag)
Primärer VRAM: 16384 MB
Soundkarte:
Audiogerät: USB Mixer
Arbeitsspeicher:
RAM: 32016 MB
VR-Hardware:
VR-Headset: Nicht gefunden
Sonstiges:
UI-Sprache: Deutsch
SPRACHE: de_DE.UTF-8
Verfügbarer Festplattenspeicher insgesamt: 937498 MB
Größter freier Festplattenspeicherblock: 270551 MB
Speicherplatz:
Anzahl SSDs: 3
SSD-Größen: 1000G,1000G,500G
Anzahl Festplatten: 0
Anzahl der Wechseldatenträger: 0
LLazyWings 2024-10-14 github

Replying to https://github.com/ValveSoftware/Proton/issues/8072#issuecomment-2405735800

Hi - sorry, I've been busy so not been able to respond, but you found out it was a Manjaro/Arch problem unrelated to this. Hopefully that's resolved now. In future, you could maybe try the flatpak version of Steam if you run into any issues like that, until they get resolved.

More generally, I wanted to comment that the command I put is what works for me! I'm hoping most people know this but I know some people might just run into an issue and randomly start throwing out commands and environments they've copy pasted. I was quickly trying to get the game to work during my lunch break that day so just rushed out a response. I should have probably put: SteamDeck=1 gamescope [options] -- %command%.

For those that don't know:

  • -h sets the internal resolution height, defaulting to 16:9 if -w is undefined.
  • -r sets the gamescope refresh rate. So that means my monitor is 1440p with 165hz refresh rate. You can launch gamescope at higher internal resolutions and such, but you'll just be wasting resources.
  • --force-grab-cursor is something I use specifically for Space Marine 2 because there's a bug with multimonitor that breaks the cursor grab. I can still change window and free my cursor, but this just prevents the bug. I recommend it for SM2.
  • You can also add other commands, see gamescope --help in a terminal for a full list.

I also should have clarified that the variable sets your graphics settings to what it considers Steam Deck optimised, but you can change it to whatever you want. I just didn't know whether it disabled DLSS or not, but seems like it just works and correctly recognises your graphics drivers, so it's all good.

Steam overlay is the only major outstanding issue for this game on Linux I believe. Which is weird because the Epic Games overlay works if you link your account.

Mmathew2214 2024-10-15 github

Steam Deck LCD
SteamDeck=1 %command%
GE-Proton9-15
"SteamOS Holo" (64 bit)
Kernel Name: Linux
Kernel Version: 6.5.0-valve21-1-neptune-65-g33487bf05ed3
X Server Vendor: The http://X.Org Foundation
X Server Release: 12101011
X Window Manager: KWin
Steam Runtime Version: steam-runtime_0.20240806.97925
Video Card:
Driver: AMD AMD Custom GPU 0405 (radeonsi, vangogh, LLVM 16.0.6, DRM 3.57, 6.5.0-valve21-1-neptune-65-g33487bf05ed3)
Driver Version: 4.6 (Compatibility Profile) Mesa 24.0.5 (git-09d9c2fd7f)

game runs and appears to be stable, but the framerate is unbearable.

HHadrianneue 2024-10-20 github

devs borked linux again, ever since WWZ this engine in particular struggles on linux smh, already tried 6.11, lts, same issue, crashes while loading a game, was working fine a few weeks ago, steamdeck=1 makes connection error go away but doesn't fix loading.

OS: EndeavourOS
GPU: Radeon RX 6700 XT
Kernel version: 6.12.0-rc1-1-mainline (6.11 or even lts 6.6 no difference)
Mesa version: 24.3.0-devel (doesn't matter, even stable crashes)
Desktop environment: KDE
Proton experimental, bleeding edge, proton-9, doesn't matter which proton version i use.

steam-2183900.log

NNaitrate 2024-10-22 github

The game keeps freezing for me at the seizure warning screen. Anyone got a fix for this? I tried the cinematic skip launch parameter and the SteamDeck=1 environment variable without any luck.

EDIT: For some reason disabling cloud saves did the trick.

Ssigzegv 2024-10-22 github

The game keeps freezing for me at the seizure warning screen. Anyone got a fix for this? I tried the cinematic skip launch parameter and the SteamDeck=1 environment variable without any luck.

EDIT: For some reason disabling cloud saves did the trick.

did you disable the steam overlay ?

LLazyWings 2024-10-22 github

The game keeps freezing for me at the seizure warning screen. Anyone got a fix for this? I tried the cinematic skip launch parameter and the SteamDeck=1 environment variable without any luck.

EDIT: For some reason disabling cloud saves did the trick.

As the person above said, disable Steam Overlay. Also turn off Mangohud and any other overlays you might have running. For some reason the only overlay the game likes on Linux is the Epic one. I also recommend Proton Experimental. I've found it crashes the least with that proton version. I've not tried GE9-16 but I had issues with GE9-15 and GE9-14.

Dd3vilguard 2024-11-16 github

This game seem to also affected by HansKristian-Work/vkd3d-proton#1406. launching the game with VKD3D_CONFIG=no_upload_hvv %command% have ~20% fps improvement for me.

this isn't a solution and is more of a band-aid. It actually makes heavily CPU dependent scenes run with even less FPS. GPU utilization is a bit better but still far from perfect.

CCptCookies12 2024-12-19 github

Wanted to make more of a comprehensive report regarding a severe performance issue the game's had since launch on Proton. There's something wrong with GPU utilization on this game under Proton that results close to a 45% performance difference compared to how the game runs natively on Windows.

While I only have logs and screenshots as of the game's current version (Hotfix 5.1) running on my RTX 4070 Super, I know that while I was still running an RX 6700 XT I was having the same or similar issues back when the game first came out a few months ago.

VKD3D_CONFIG=no_upload_hvv only partially helps performance and it depends on the scene, so I don't believe Resizable BAR is the only culprit that's going on with this game regarding performance. Besides testing with that variable on and off, another confirmation for GPU utilization issues is that resolution scaling generally does not affect performance no matter what setting it's set to. Any lower resolutions simply lower GPU usage and power, and in some scenes it can actually cause a minor performance regression as shown in the later screenshots. These were all ran at Ultra preset with FSR upscaling set to Quality (barring the Ultra Performance comparison).

Windows Proton Proton (no_upload_hvv)
Warhammer_40000_Space_Marine_2_-_Retail_b6SVyhWgyS Screenshot_20241219_020243 Screenshot_20241219_015527
Warhammer_40000_Space_Marine_2_-_Retail_0123WgRrBB Screenshot_20241219_020423 Screenshot_20241219_015702
Proton, FSR Ultra Performance Proton, FSR Ultra Performance (no_upload_hvv)
Screenshot_20241219_020437 Screenshot_20241219_015811

Proton log: steam-2183900.tar.gz
Proton (no_upload_hvv) log: steam-2183900_no-upload-hvv.tar.gz

If anyone else can help confirm this issue, would be greatly appreciated! Especially from AMD GPU users, because I don't have access to my RX 6700 XT anymore and can't directly find out if exactly the same issue and performance numbers are present there.

System Information

OS: "Fedora Linux 41 (KDE Plasma)" (64 bit)
GPU: NVIDIA GeForce RTX 4070 Super
Video driver version: NVIDIA 565.77
Kernel version: 6.12.4-200.fc41.x86_64
Link to full system information report as Gist: https://gist.github.com/CptCookies12/b2c753f8248d5c95cfe7f6dd0a87ac69
Proton version: experimental-9.0-20241217

HHadrianneue 2024-12-19 github

Replying to https://github.com/ValveSoftware/Proton/issues/8072#issuecomment-2553355068

Tested using a 6700xt with mesa-git vs windows 11 on a 5700X3D both with SAM on.

Game has terrible performance on windows/linux. gpu usage is lower on linux indeed, albeit with not so large performance differences, it trades blows all around.

So it doesn't affect AMD GPUs just as much but its definitely a tad slower than windows (it can be faster at times), another factor is the CPU bottleneck as well....

1-linux 1-windows
Linux Windows
1-linux 1-windows
Linux Windows
1-linux 1-windows
Linux Windows
Mmathew2214 2025-01-15 github

how are you guys getting the game to launch?
see https://github.com/ValveSoftware/Proton/issues/8072#issuecomment-2547299252

update: using GE-Proton8-32, the game launches, and i get to title screen, but it crashes as soon as i press enter.
proton log: https://gist.github.com/mathew2214/7646f8304f6bb914fa33e481e956286a/

attached is the zip file generated by the game's crash reporter. examining which is far above my skillset.
crash_data.zip

NNaitrate 2025-01-16 github

Replying to https://github.com/ValveSoftware/Proton/issues/8072#issuecomment-2593697700

At least on a desktop, I disable the in-game overlay in the properties for the game on Steam.

Mmathew2214 2025-01-18 github

Replying to [#8072 (comment)](https://github.com/ValveSoftware/Proton/issues/8072#issuecomment-2593697700)

At least on a desktop, I disable the in-game overlay in the properties for the game on Steam.

yeah, im doing it with steam overlay disabled. no difference.

Nneon-grim 2025-02-11 github

I started playing the game again, now that it support 32:9 and I noticed that the issue I reported in my previous comment is still present. Has anyone encountered this?

Mmathew2214 2025-05-23 github

using proton ge 10-3, i still cannot play the game on Debian.

proton log: https://gist.github.com/mathew2214/b2a895b4e4bda2e70961a98e23920ea0

system info: https://gist.github.com/mathew2214/af2665fd7772f408d506b518053466d1

using Valve's proton 10 also yields identical results.
valve, please fix.

SSpike1978 2025-08-09 github

This game will get slower and slower with FPS over time, starting with full 60fps i end up with average 45 FPS after doing 3 missions and the longer i play it becomes more and more unplayable. I tried on Windows and there are no FPS slowdowns over time with the same hardware.
It happens with all the Proton versions i tried, Proton experimental and Proton GE

PC Specs: AMD Ryzen 7 5800X3D , GeForce RTX 2080 , 32GB RAM

Aalosarjos 2025-11-09 github

Looks like there is some kind of regression maybe on Proton Experimental with this game. I've been using the AMD stub to force FSR4 by using the DLL from AMD and FSR4_UPGRADE=1 with DXIL_SPIRV_CONFIG=wmma_rdna3_workaround

And this has been working perfectly for near more than a month, but now suddenly it started crashing the game. There have been no patches for the game in a month, but there was a Proton Experimental update a few days ago (Maybe yesterday?).

BBillli11 2025-11-09 github

@alosarjos May be related https://github.com/HansKristian-Work/vkd3d-proton/pull/2679

Default build of vkd3d-proton now disable fp8 emulation by default.

FP16 version of fsr4 work though.

Aalosarjos 2025-11-29 github

Really bad framerate drops since last patch. Not sure if a bug on the game, or something the game using now that has some issue on Proton.

Sslothyyy 2025-11-29 github

Big fps drops and loading the game assets seems to be really broken after the last patch where loading screens take about 10x longer and switching your graphics settings take an eternity.

I expect this is down to the developers of the actual game tho

Aalosarjos 2025-11-29 github

Big fps drops and loading the game assets seems to be really broken after the last patch where loading screens take about 10x longer and switching your graphics settings take an eternity.

I expect this is down to the developers of the actual game tho

I'm not reading about Windows users having theses issues...

Aalosarjos 2025-11-29 github

There are some zones where Framerate will just do down forever. I took a screenshot showing how machine resources are not at full usage while having really bad framerate. Not sure if this helps somehow.

Image
DDrymarchonShaun 2025-12-02 github

@alosarjos I think I'm seeing something similar, out of curiosity, does it still happen with EAC disabled?

if you don't already know how, the easiest way to disable it is to open the Warhammer 40000 Space Marine 2.ini file that's in the game's root directory and change ApplicationPath=start_protected_game.exe to ApplicationPath=client_pc\root\bin\pc\Warhammer 40000 Space Marine 2 - Retail.exe

Aalosarjos 2025-12-02 github

@alosarjos I think I'm seeing something similar, out of curiosity, does it still happen with EAC disabled?

if you don't already know how, the easiest way to disable it is to open the Warhammer 40000 Space Marine 2.ini file that's in the game's root directory and change ApplicationPath=Warhammer 40000 Space Marine 2.exe to ApplicationPath=client_pc\root\bin\pc\Warhammer 40000 Space Marine 2 - Retail.exe

I will give it a try later. But sadly things have gone worse. On operations, I "only" get huge FPS drops, but on the waves survival mode, 3 times I tried playing, 3 times my GPU crashed putting me back on the Gnome login screen.

Worse thing about this is not knowing if it's a game issue, or a Linux issue.

Don't want to report issues for unsupported platform to devs

But neither want to report issues on mesa o VKD3D when all issues seems to come from the latest game patch

Any advice on how should I proceed @kisak-valve ?

DDrymarchonShaun 2025-12-02 github

Based off my testing, and assuming we have the same issue, I suspect EAC might be involved, after bypassing it (which launches the game in an offline/"modded" mode) I wasn't seeing any of the choppiness I was getting with it.

It's acting almost like I'd expect from a game on an HDD, despite being on my NVME

Kkisak-valve maintainer 2025-12-03 github

Space Marine 2 Fps loss after patch 11

Issue transferred from https://github.com/ValveSoftware/Proton/issues/9278.
@xarabenari-prog posted on 2025-12-03T15:11:43:

Compatibility Report

  • Name of the game with compatibility issues: Space Marine 2
  • Steam AppID of the game: 2183900

System Information

  • CPU: Ryzen 7 7600
  • RAM: 32GB DDR5
  • STORAGE: 1TB NVME SSD
  • GPU: Rx 9060XT 16gb
  • Video driver version: MESA 25.2
  • Kernel version: 6.17.9-2-cachyos
  • Proton version: Any. (Proton 10.0-3, GE-PROTON10-25, PROTON EXPERIMENTAL...)

I confirm:

  • [ X] that I haven't found an existing compatibility report for this game.
  • [ X] that I have checked whether there are updates for my system available.

Symptoms

After patch 11, the game experiences huge frame rate drops for a few seconds before recovering.

It goes from a stable 70 FPS to 5-6 FPS for two or three seconds. Similarly, during moments of frame rate drop, the sound becomes choppy.

This happens frequently or when loading new environments or particles. I can't find a pattern to the cause.

I've tried various versions of Proton and different graphics settings, and I've also tried removing the shaders to force them to reload, but so far, no solution has been found.

Reproduction

Install the latest version of Space Marine 2 released on Steam and run it under the Proton compatibility layer.

Xxarabenari-prog 2025-12-03 github

Based off my testing, and assuming we have the same issue, I suspect EAC might be involved, after bypassing it (which launches the game in an offline/"modded" mode) I wasn't seeing any of the choppiness I was getting with it.

It's acting almost like I'd expect from a game on an HDD, despite being on my NVME

Good afternoon, I've tried the suggested solutions, and I can confirm that the FPS drop issue has been resolved. The problem now is that I obviously can't play online.

Thanks

Aalosarjos 2025-12-03 github

@DrymarchonShaun My .ini was pointing to the start_protected_game.exe instead, but changed to the values you said, and yes, now it's running flawlessly. So yeah, related to the EAC, though I think it's affecting Linux way harder than Windows

FFIGBird 2025-12-03 github

Just stopping in to report that I also ran the test with disabled EAC to find the same results.

It is unclear to me who to report the issue to, exactly, so if there is another space we should be documenting this finding let me know.

Edit: recent hotfix did not resolve the issue for me.

I also asked my buddy on windows if he's been having any of the issues and there does appear to be a few specific places where this happens to him, so it may actually be a game issue that is worse for linux as noted above.

Aalosarjos 2025-12-04 github

Still having same issues with Hotfix 11.1

JJMarcosHP 2025-12-12 github

Same issue here, fresh copy of Space Marine 2.

My system configuration:

OS: openSUSE Tumbleweed, Mesa 25.3.1 (from Packman repo), Kernel 6.18.0, ProtonGE 10.26
CPU: Ryzen 7 5700X@4700MHz all core, 1.35v fixed
RAM: 32GB DDR4 3600MT/s
GPU: MSI MECH RX 7600

All my games are installed in a nvme 1TB PCIe 4.0 with BTRFS as filesystem. When the game load the assets (it takes about 5 mins to load into the lobby) my audio starts crackling and all the cpu cores kick the %100 of usage.

No mather what configuration preset I use (Low, Medium, High), after 10 - 20 mins, my FPS drop from 120/140 to 35/50 fps depending on the number of enemies and map zones.

Kkmezn 2025-12-16 github

patch 11.2 released on steam. issue still persisting for me. (EAC enabled in order to play online) https://store.steampowered.com/news/app/2183900/view/492711197218439388?l=english

Mmathew2214 2025-12-28 github

Debian 13. game is unlaunchable normally. i have to do the ini edit to run Retail exe in order for game to even start.

TTheEpicNoobZilla 2026-01-02 github

Game works with latest patch, but suffers from constant FPS drops (from 60 to single digits). When the game drops the GPU usage drops to almost 0% while CPU goes up to almost 100%. Also the game sometimes fails to launch due to EAC errors. Loading missions can take some time, but it might be due to networking issues

Rrejedai 2026-01-03 github

Game breaks pipewire on every loading.

Kkisak-valve maintainer 2026-01-04 github

Space Marine 2: Game freezes during cutscenes (NtGdiDdDDIQueryStatistics polling loop)

Issue transferred from https://github.com/ValveSoftware/Proton/issues/9368.
@taqd posted on 2026-01-04T08:48:27:

Compatibility Report

  • Name of the game with compatibility issues: Warhammer 40,000: Space Marine 2
  • Steam AppID of the game: 2183900

System Information

  • GPU: NVIDIA GeForce RTX 3080 Ti Laptop GPU
  • Video driver version: 580.95.05
  • Kernel version: 6.14.0-37-generic
  • Proton version: Tested with Proton Experimental, Proton 9.0 Beta, GE-Proton10-28, Proton Hotfix

I confirm:

  • [x] that I haven't found an existing compatibility report for this game.
  • [x] that I have checked whether there are updates for my system available.

Symptoms

Game freezes completely during in-game cutscenes. When starting New Game or Continue, the intro cinematic begins and the game immediately becomes unresponsive. No keyboard or mouse input works (including Escape). No error messages or popups appear. The game must be force-killed.

Analysis of the Proton log shows a single thread (0224) stuck in a tight polling loop at 100% CPU:

0224:fixme:x11drv:X11DRV_D3DKMTQueryAdapterInfo desc 0x21cff570, type 3 stub
0224:fixme:driver:NtGdiDdDDIQueryStatistics (0x21cff8d0): stub
0224:fixme:driver:NtGdiDdDDIQueryStatistics (0x21cff8d0): stub
[repeats indefinitely]

The game's Streamline/DLSS integration appears to poll NtGdiDdDDIQueryStatistics for performance metrics. Since Wine returns nothing from this stub, the thread spins forever.

Reproduction

  1. Launch Space Marine 2 via Steam with any Proton version listed above
  2. From the main menu, click "New Game" or "Continue"
  3. Game freezes immediately when the cutscene starts

Workarounds Attempted (all failed)

  • Disabled Steam Overlay (globally and per-game)
  • Disabled DLSS and Frame Generation in-game
  • PROTON_ENABLE_NVAPI=0
  • PROTON_HIDE_NVIDIA_GPU=1
  • VKD3D_CONFIG=no_upload_hvv
  • SteamDeck=1
  • Deleted shader cache
  • Deleted entire Wine prefix (fresh install)

Attachments

DDrymarchonShaun 2026-01-04 github

@taqd does this happen to mitigate your issue?

I think I'm seeing something similar, out of curiosity, does it still happen with EAC disabled?

if you don't already know how, the easiest way to disable it is to open the Warhammer 40000 Space Marine 2.ini file that's in the game's root directory and change ApplicationPath=start_protected_game.exe to ApplicationPath=client_pc\root\bin\pc\Warhammer 40000 Space Marine 2 - Retail.exe

worth noting, this means the game launches in offline/modded mode, so online play isn't possible and progress doesn't save. This can be reverted easily by editing the mentioned file back to what it was originally, however.

XxEnSei 2026-01-07 github

I tested Proton Experimental.
I played one round and defeated the Swarm Tyrant. There were significant performance drops during startup and loading screens, with the loading screen for the mission taking a particularly long time.
During the mission with other players, there were occasional freezes and stutters.

It has gotten better, but there is still a lot of room for improvement.

Kkisak-valve maintainer 2026-01-09 github

Space Marine 2: periodic main-thread stalls after Update 11 with EAC enabled (Proton regression)

Issue transferred from https://github.com/ValveSoftware/Proton/issues/9379.
@Kyrottimus posted on 2026-01-09T00:39:28:

Compatibility Report

  • Name of the game with compatibility issues: Warhammer 40,000: Space Marine 2
  • Steam AppID of the game: 2183900

System Information

• OS: Manjaro Linux (XFCE)
• Kernel: 6.6.119-1-MANJARO
• Desktop: XFCE 4.20 (X11)
• CPU: AMD Ryzen 9 7945HX (32 logical cores)
• RAM: 32 GB
• GPU: AMD Radeon RX 7600M XT (Navi 33)
• Driver: amdgpu (kernel)
• Mesa: 25.3.2-arch1.1
• Vulkan: 1.4.335
• Vulkan Driver: RADV (Mesa)
• OpenGL: 4.6 (radeonsi, LLVM 21.1.6)
  • Proton version: Proton 9.0-4, 10.0-3, Experimental, Hotfix, GE-Proton 10-28 were all tested (GE 10-28 had most severe stuttering)

I confirm:

  • [X] that I haven't found an existing compatibility report for this game.
  • [X] that I have checked whether there are updates for my system available.

steam-2183900.log

Also, as a point of note, see

https://www.protondb.com/search?q=space marine 2

for a large number of other reports indicating the same symptoms described in this report.

Game
• Warhammer 40,000: Space Marine 2
• Regression introduced after Update 11
• Prior to Update 11, the game ran flawlessly under Proton on this system.

Symptoms

Description of the Problem
After Update 11, the game exhibits periodic main-thread stalls during missions when Easy Anti-Cheat (EAC) is enabled under Proton.

Observed behavior:
• Frequency: every ~30 seconds to 2 minutes
• Duration: typically 1–4 seconds (after mitigation)
• FPS drops to ~15–20 during stalls
• Complete input stall during events (mouse and keyboard unresponsive)
• GPU utilization drops during stalls but appears secondary

Disabling EAC removes the issue entirely, but there is no way to save progression in-game with EAC disabled so this is not an ideal solution.

Mitigation Findings
• CPU saturation significantly worsens stall severity
• Applying systemd CPUQuota reshapes behavior:
◦ Stall severity and duration are reduced
◦ Stall frequency increases
• Disabling frame generation removes input lag but does not remove stalls
• Alt+Enter temporarily clears the stall
• GPU-side mitigations do not resolve the issue

This strongly suggests a periodic EAC-related memory or synchronization operation blocking the game’s main thread, likely introduced by Update 11’s “memory handling improvements”.

Reproduction

Reproduction Steps
1. Launch Space Marine 2 under Proton with EAC enabled
2. Enter any mission, play through mission.
3. Observe periodic stalls during gameplay

KKyrottimus 2026-01-09 github

Replying to https://github.com/ValveSoftware/Proton/issues/8072#issuecomment-3726575632

Note: the issue I reported was auto-merged here, but the symptoms are different from the original description.

My experience is not a connection/authentication failure — the game loads + runs under Proton Experimental, but after Update 11 which was released for Space Marine 2 on November 25, 2025, it exhibits periodic main-thread stalls while playing missions with EAC enabled:

• Frequency ~30s – 2min
• Duration ~1–4s
• Input freezes + FPS drops
• Disabling EAC eliminates the problem
• CPU scheduling mitigations reshape but do not remove the stalls
• Extensive log attached previously shows high resource churn and view map pressure under DX12 + vkd3d

This appears to be a performance regression after Update 11, not the original connection issue.

I can provide additional logs or traces if helpful.

LLuxLucian 2026-01-16 github

I am using an AMD CPU and GPU, and tried disabling SMT in my bios. It did not fix the performance drops, but hte load times were much more stable and the performance drops did not last as long or occur as frequently. This might be a workaround for the time being.

CachyOS
GPU - 5700 XT
CPU - 3600

CCatOfTheCode 2026-01-20 github

Ever since Update 11, I haven't been able to play online. Whether I'm in Public or Private, the game says I'm running mods (I've never used a mod on this game) and kicks me out of the 'public' game - even if I'm in Private. I can only play Solo.

And apparently I'm not the only one. Both the Steam Forums and the Focus forums are full of people reporting this. It does not appear to be associated with the AZW servers being unstable, which was what got the blame for this pre-U11. But afaict, all the reports of perma-Mod Detected since U11 appear to be Linux users. And Focus appears to be either uninterested or incapable in fixing it, despite the issue seeming to be directly caused by U11 detected Proton as a false positive for mods.

DDrymarchonShaun 2026-01-29 github

Note: the issue I reported was auto-merged here, but the symptoms are different from the original description.

@Kyrottimus you might already know this, but issues in this repo are per-game, not per-bug. So any issues related to SM2 go in this issue, even if the original reason the issue was created is different from what you are experiencing. The more recent comments in this thread are discussing the issue you are dealing with.

Aalosarjos 2026-01-29 github

Is there any other news regarding to this game? I find hard to believe it's a 100% issue on the game or everyone would be unable to play this for months already...

Kkmezn 2026-01-29 github

Is there any other news regarding to this game? I find hard to believe it's a 100% issue on the game or everyone would be unable to play this for months already...

Nothing working on live as far as i know however there is a pts up for the new patch. Looking through the notes aside from memory and stability fixes i couldn't see anything about eac issues.

Pts notes here: https://community.focus-entmt.com/focus-entertainment/space-marine-2/blogs/339-pts-patch-notes-12-0

Cchef-dan 2026-02-06 github

Summary

Space Marine 2 (AppID 2183900) on Linux regressed with Patch 11 on my setup: very long loading
times, severe frame drops/stutter (especially cutscenes), and occasional crashes.
Performance improved substantially with GE-Proton and split-lock mitigation workaround, but stability
is still not perfect.

System Information

  • OS: Fedora Linux 43 (KDE Plasma Desktop Edition)
  • Session: Wayland
  • Kernel: 6.18.7-200.fc43.x86_64
  • CPU: Intel Core i7-12700K
  • RAM: 31 GiB
  • GPU: NVIDIA GeForce RTX 3080 Ti (GA102)
  • NVIDIA driver: 580.119.02
  • Secondary GPU: Intel UHD 770
  • Game: Warhammer 40,000: Space Marine 2 (Patch 11)

Proton Versions Tested

  • Proton Hotfix
  • GE-Proton10-29 (best result so far)

Repro / Symptoms

  1. Launch game with Proton (Hotfix or GE).
  2. Observe startup/loading and cutscene performance.
  3. On default kernel split-lock behavior, experience severe stalls/frame drops.
  4. Occasional crash can occur during/after heavy stutter periods.

What I Observed in Logs

  • Repeated kernel split-lock events from game/Wine threads:
  • x86/split lock detection: #AC: Warhammer 40000 ...
  • Earlier crash session also showed:
  • NVRM: Xid (PCI:0000:01:00): 13, pid=..., name=Warhammer 40000, Graphics Exception ...

Workaround That Helped a Lot

  • Switch to GE-Proton10-29
  • Dynamically set:
  • kernel.split_lock_mitigate=0 while Steam game process is running
  • restore to kernel.split_lock_mitigate=1 on exit

This significantly reduced load-time stalls and improved in-game/cutscene smoothness, but did not
fully eliminate crashes.

Current Status

  • Playability: much better with workaround
  • Remaining issue: occasional crash / not fully stable
  • Not yet “works perfectly out of the box” on this hardware/software combo
Xx5f3759df 2026-02-15 github

I had an issue when game used 100% of my CPU and render like 5-7 fps. Disabling split lock mitigation fixed that issue. Previously I used gamemode that can disable it automatically, so I never seen this before I switched to falcond.

Aazahi 2026-02-26 github

EAC issue with high CPU usage and FPS drops on loading before and mid-game still persists as of patch 12.0.

Aazahi 2026-02-28 github

A combination of scx_bpfland, gamemode and proton-cachyos-slr reduced stuttering to 2-3 seconds on average per PvE match. High CPU usage and load times are still abysmal compared to what was before patch 11.0. The main culprit is still EAC.

II3lackEye 2026-03-01 github

System Information

|  
-- | --
OS | CachyOS (KDE Plasma Desktop Edition)
Session | Wayland
Kernel | 6.19.5-3-cachyos
Scheduler | scx_bpfland
CPU | AMD Ryzen 7 5800X
RAM | 32 GiB
GPU | NVIDIA GeForce RTX 5070 Ti
NVIDIA Driver | 590.48.01
Proton Version | proton-cachyos-10.0.20260207-slr

Description

On initial load into a mission, the CPU is pegged at 100% utilization and the framerate drops to 5–7 FPS. The game does not recover on its own — it stays in this degraded state indefinitely.

A full game restart resolves the issue immediately and completely. Performance returns to normal for the next mission. The workaround is 100% reliable.

Additionally, during loading screens, audio crackling/popping is consistently audible. This may be related to the same underlying CPU usage spike.

I also experience the stuttering issues reported by other users in this thread.

Reproduction Steps

  1. Launch Space Marine 2 via Proton
  2. Starting a mission from the HUB
  3. CPU usage spikes to 100%, FPS drops to 5–7
  4. Intro cutsecene gets a stuck at 1-2 fps
  5. Game remains unplayable until fully restarted

Expected: Game loads into mission with watchable cutscene and playable perfomance Actual: CPU maxes out, game is unplayable. Restart required after every mission.


Additional Notes

  • Issue is consistent and reproducible for every mission
  • Restart workaround is fully effective — no degradation carries over
  • Audio crackling during loads is present regardless of the CPU spike
  • All three symptoms (CPU spike, audio crackling, stutter) appear to be part of the same regression introduced with patch 11
Aazahi 2026-03-04 github

scx_cosmos fixed pretty much all stuttering for me. Pure magic!

Aamz-x 2026-03-05 github

scx_cosmos fixed pretty much all stuttering for me. Pure magic!

Can also confirm that using scx_cosmos scheduler fixed the stuttering for me too.

I implemented the the following on NixOS:

# Services
# https://search.nixos.org/options?channel=unstable&show=services
services = {

  # Services - SCX
  # https://search.nixos.org/options?channel=unstable&show=services.scx
  scx = {

    # Services - SCX - Enable
    # https://search.nixos.org/options?channel=unstable&show=services.scx.enable
    enable = true;

    # Services - SCX - Scheduler
    # https://search.nixos.org/options?channel=unstable&show=services.scx.scheduler
    scheduler = "scx_cosmos";
  };
};

JJMarcosHP 2026-03-05 github

I'll try the cosmos scheduler, I'm currently using lavd.

JJMarcosHP 2026-03-05 github

scx_cosmos fixed pretty much all stuttering for me. Pure magic!

Do you use any custom flags for cosmos or just the defaults?

Aazahi 2026-03-05 github

Do you use any custom flags for cosmos or just the defaults?

https://wiki.cachyos.org/configuration/sched-ext/#gaming

Qquiescens 2026-03-05 github

Anecdotally, switching to scx_cosmos (with otherwise default settings FWIW) does appear to fix the biggest issue I was seeing.
It does still feel like it runs overall a little less well than it does on windows but "slightly slower" is much more playable than "randomly runs at 1fps for 5-15s at a time".

It is a strange workaround though, as there was also a data point saying that turning off the anticheat also resolves the issue (albeit removing the ability to multiplayer).
Combined with this discovery it indicates that the anticheat is potentially having some sort of issue that scx_cosmos mitigates?

It might be interesting to see which (if any) other schedulers also mitigate/resolve this issue, and if so (or not), potentially identify why.
Is something causing some kind of absolute worst case result in the default scheduler, or does scx_cosmos do something that happens to mitigate it?

JJMarcosHP 2026-03-05 github

After 1hr of gameplay I can confirm that the cosmos scheduler mitigates almost all the current issues. No more audio crackling while loading mission assets, no more low fps or drops. CPU usage in all cores is consistent during the gameplay with no performance degradation. I don't have any custom flags for cosmos.

Operating System: openSUSE Tumbleweed 20260304
KDE Plasma Version: 6.6.2
KDE Frameworks Version: 6.23.0
Qt Version: 6.10.2
Kernel Version: 6.19.5-1-default (64-bit)
Graphics Platform: Wayland
Processors: 16 × AMD Ryzen 7 5700X 8-Core Processor
Memory: 32 GiB of RAM (31.3 GiB usable)
Graphics Processor: AMD Radeon RX 7600
Image Image
DDrymarchonShaun 2026-03-05 github

Interesting, I'm seeing the same thing. I just set up scx_cosmos and the game just... works.

Since some of y'all seem to be more familiar with it, is there any downside to just using scx/sched-ext all the time?

EDIT- actually, I think it may just be that the game is working now, even without any of the schedulers the game seems to be running fine for me.

JJMarcosHP 2026-03-06 github

Interesting, I'm seeing the same thing. I just set up scx_cosmos and the game just... works.

Since some of y'all seem to be more familiar with it, is there any downside to just using scx/sched-ext all the time?

I don't see any issue here by using a custom scheduler, cosmos can handle different types of workloads, it's a general purpose scheduler.

LLuxLucian 2026-03-06 github

I can also say that using the scx_cosmos scheduler works on my end. Using CachyOS with AMD an AMD 3600 CPU and 5700 GPU.

DDrymarchonShaun 2026-03-06 github

I can also say that using the scx_cosmos scheduler works on my end. Using CachyOS with AMD an AMD 3600 CPU and 5700 GPU.

Did you happen to check if it still wasn't working without scx_cosmos?

ZZeronthe 2026-03-07 github

For those monkeys like me on non cachy arch distros and trying to find a "simple" way to implement changing your scheduler :

Install:

sudo pacman -S scx-scheds

Once installed, simply run this in terminal before starting the game:

sudo scx_cosmos

Leave the terminal open the whole time, you can ctrl+c to close it afterwards if you don't want the scheduler to be changed all the time.

edit: can confirm, game is completely playable with the new scheduler running.

Did notice that as the game stays open, performance degrades over time until you restart the game, might be NVIDIA specific though.

Cchimera74 2026-03-17 github

Fixed problem

Space Marine 2 crashes/freezes immediately after the first cutscene (story_intro scene) on Linux with
NVIDIA RTX 5000 series GPUs. The game menu works fine, EasyAntiCheat loads successfully,
but the GPU hangs during gameplay load.

Root cause: NVIDIA driver bug (Xid 109 — CTX SWITCH TIMEOUT). Certain compute shaders in SM2 use SPIR-V
instructions that the Blackwell GPU driver can't handle, causing a context switch timeout.

How to confirm you have this issue:

journalctl -b --no-pager -p warning | grep -i "xid"

You'll see:

NVRM: Xid (PCI:0000:01:00): 109, pid=XXXXX, name=Warhammer 40000, channel 0x0000000a, errorString CTX
SWITCH TIMEOUT, Info 0xc006

The Fix: pyroveil

Pyroveil is a Vulkan layer that rewrites problematic shaders through SPIRV-Cross, making them
compatible with the NVIDIA driver.

  1. Install dependencies
sudo pacman -S ninja cmake gcc git
  1. Build and install pyroveil
git clone --recursive https://github.com/HansKristian-Work/pyroveil.git ~/pyroveil
cd ~/pyroveil
mkdir -p build
cd build
cmake .. -G Ninja -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=$HOME/.local
ninja
ninja install
  1. Create SM2 config
    Create ~/pyroveil/hacks/space-marine-2-nv/pyroveil.json:
{
	"version": 2,
	"type": "pyroveil",
	"matches": [
			{ "spirvExecutionModel": 5, "action": { "glsl-roundtrip": true } }
	],
	"roundtripCache": "cache",
	"disabledExtensions": [ "VK_NV_raw_access_chains" ]
}

Then create the cache directory:

mkdir -p ~/pyroveil/hacks/space-marine-2-nv/cache
  1. Set Steam launch options
    Right-click SM2 → Properties → Launch Options:
PYROVEIL=1 PYROVEIL_CONFIG=~/pyroveil/hacks/space-marine-2-nv/pyroveil.json DXVK_ASYNC=1 %command%

What this does:

  • Roundtrips all compute shaders through SPIRV-Cross, rewriting the SPIR-V instructions that trigger
    the Nvidia driver bug
  • Disables VK_NV_raw_access_chains (another Nvidia compatibility issue)
  • Caches rewritten shaders so only the first launch is slower

Environment tested on:

  • CachyOS (Arch-based), kernel 6.19.7
  • NVIDIA RTX 5060 Ti, driver 595.45.04 (open kernel modules)
  • Proton Experimental / GE-Proton
  • Space Marine 2 Patch 12

Notes:

More detail:
The problem is that VKD3D-Proton generates valid but unusual SPIR-V patterns (especially around subgroup/wave operations in compute shaders) that NVIDIA's Windows driver never sees. The Blackwell driver's SPIR-V compiler has a bug where certain patterns cause the GPU to hang during context switching.
Pyroveil fixes it by roundtripping the SPIR-V through SPIRV-Cross (decompile to GLSL, recompile back to SPIR-V). This produces equivalent but more "conventional" SPIR-V that the driver handles fine.

Kkisak-valve maintainer 2026-03-17 github

Warhammer 40000 Space Marine 2 wont run on 2nd SSD

Issue transferred from https://github.com/ValveSoftware/Proton/issues/9585.
@target-bravo posted on 2026-03-17T13:50:35:

Compatibility Report

  • Name of the game with compatibility issues: Warhammer 40000 Space Marine 2
  • Steam AppID of the game: 2183900

System Information

I confirm:

  • [x ] that I haven't found an existing compatibility report for this game.
  • [x ] that I have checked whether there are updates for my system available.

steam-2183900.log

Symptoms

Game will not launch when installed to the second NVME on my system and will give the error "failed to get process path" from easy anticheat, but it will launch when installed on the system SSD. all other games installed on the second SSD run well claire obscura, sniper elite 5, helldivers 2 etc

Reproduction

I have reinstalled steam os and done a complete wipe of the second ssd and the issue is identical. wierd secondary issue with steam is that the game will not move between locations i have to uninstall and install each time as it declares that a file is busy.

Ttarget-bravo 2026-03-17 github

Replying to https://github.com/ValveSoftware/Proton/issues/8072#issuecomment-4075172775

I forgot to add that the game was working on the second SSD to which i did about 1/2 a second playthrough then after about 2 steam OS updates it would give me the error

Kkisak-valve maintainer 2026-03-17 github

Hello @target-bravo, can you check how the game behaves with the game's launch options set to PROTON_SET_GAME_DRIVE=1 %command%? (from https://github.com/ValveSoftware/Proton/issues/1651#issuecomment-3814151296)

Ttarget-bravo 2026-03-17 github

Hello @target-bravo, can you check how the game behaves with the game's launch options set to PROTON_SET_GAME_DRIVE=1 %command%? (from [#1651 (comment)](https://github.com/ValveSoftware/Proton/issues/1651#issuecomment-3814151296))

Same issue sadly

Image
Ttarget-bravo 2026-03-17 github

Ok i think i have it sorted after 3 days of trial and error.

I previously set up a folder /run/media/deck/Games/ then setup the drive to mount to this location in KDE partition manager like SD-Cards.

when like this the game would give me the above error.... but only recently for some reason

I then unmounted the drive removed the folder and that mount point from kde partition manager and double clicked the drive to mount it.

Space Marine 2 now launches fine but the drive does not auto mount anymore.

Now for the weird fix mounting the drive by double clicking creates a folder /run/media/deck/Games/ same as above. Now if i use this folder in KDE Partition manager as the mount point Space marine 2 will launch just fine.

BbVNyDUKE 2026-03-18 github

New hotfix https://community.focus-entmt.com/focus-entertainment/space-marine-2/blogs/367-hotfix-12-2-patch-notes

  • Fixed an issue causing low FPS and 100% CPU usage on Steamdeck.

Interested to see if this will resolve the FPS and CPU issues on Linux in general, without the use of a custom scheduler.

JJMarcosHP 2026-03-18 github

Time to test

BbVNyDUKE 2026-03-18 github

New hotfix https://community.focus-entmt.com/focus-entertainment/space-marine-2/blogs/367-hotfix-12-2-patch-notes

  • Fixed an issue causing low FPS and 100% CPU usage on Steamdeck.

Interested to see if this will resolve the FPS and CPU issues on Linux in general, without the use of a custom scheduler.

Just completed the weekly normal, no issues. Looks like its fixed.

ZZeronthe 2026-03-22 github

Game performance still unfortunately degrades over time, at least for Nvidia GPUs(590 driver.) After a couple missions performance will slowly get worse until you restart the game.

Better than it was, but still not perfect.

Kkolchurinvv 2026-04-14 github

https://github.com/ValveSoftware/Proton/issues/8072#issuecomment-4071848316 - legend for posting this.

Game performance still unfortunately degrades over time, at least for Nvidia GPUs(590 driver.) After a couple missions performance will slowly get worse until you restart the game.

Nvidia driver 595.58.03
Operating System: Bazzite 43
KDE Plasma Version: 6.6.3
KDE Frameworks Version: 6.24.0
Kernel Version: 6.17.7-ba29.fc43.x86_64 (64-bit)
Graphics Platform: Wayland

didn't notice this issue. could be related to kernel/shell? in other games i noticed some settings like the vsync mess with frame timing which causes stutters at times. maybe there's an optimal way to configure the game?

ZZeronthe 2026-04-15 github

Unfortunately running the pyroveil "hack" does nothing but absolutely nuke my framerate. Updating all my packages recently still doesn't help with performance degradation, after about 2 missions i notice a subtle hit, after about 3-4, frametimes are toast and the game needs restarted. Seems to accelerate if you spend a lot of time in the armory.

Garuda Linux x86_64
Kernel: 6.19.11-zen1-1-zen
Resolution: 3440x1440 2560x1440 1920x1080
DE: KDE Plasma 6.6.4
WM: KWin (Wayland)
WM Theme: Sweet-Dark
Theme: Dr460nized (Sweet) [Qt], Sweet-Dark [GTK2/3/4]
Icons: BeautyLine [Qt], BeautyLine [GTK2/3/4]
Terminal: konsole 25.12.3
Terminal Font: FiraCode Nerd Font Mono 12
dCPU: AMD Ryzen Threadripper PRO 5975WX 32-Cores (64) @ 4.561GHz
GPU: GeForce RTX 4090
GPU: ASPEED Graphics Family
Memory: 12349MiB / 257575MiB

Running the journal command

journalctl -b --no-pager -p warning | grep -i "xid"

Returns nothing, so i'm assuming i don't share the same issue.

I use these launch options normally:

PROTON_USE_NTSYNC=1 gamemoderun __GL_SHARPEN_ENABLE=1 __GL_SHARPEN_VALUE=100 PROTON_HIDE_NVIDIA_GPU=0 PROTON_ENABLE_NVAPI=1 PROTON_NVIDIA_LIBS=1 %command%

Using latest proton GE.

Playing the game on windows for now without any issues, here's hoping it sees some improvement eventually.

Kkolchurinvv 2026-04-16 github

Unfortunately running the pyroveil "hack" does nothing but absolutely nuke my framerate.
GPU: GeForce RTX 4090

In my albeit small experience this hack is exclusively for 50x Nvidia series.
Have you tried Proton EM latest?

ZZeronthe 2026-04-16 github

I've tried other proton versions but i haven't heard of proton-em, what makes it different from GE/Cachy/stock? The github doesn't really go into detail.

Kkolchurinvv 2026-04-16 github

@Zeronthe i can't really tell. i've seen this in the tinker steps on protondb and during my attempts to launch the game i basically landed on the combo of this hack + proton EM latest. the version itself is available through the usual means on bazzite - protontricks, so seems legit enough

Image
ZZeronthe 2026-04-17 github

Unfortunately using proton-EM didn't do anything to resolve the issue here. After the third mission, like clockwork, performance started to degrade.

BBillKills974 2026-06-01 github

Compatibility Report

  • Name of the game with compatibility issues: Warhammer 40000 Space Marine 2
  • Steam AppID of the game: 2183900

System information

  • OS: Arch Linux x86_64
  • GPU: NVIDIA GeForce RTX 4080
  • Video driver version: NVIDIA Driver 610.43.02
  • CPU: AMD Ryzen 7 5800X
  • Proton version: Proton experimental (default)
  • Steam system info: System Info

I confirm:

  • [x] that I haven't found an existing compatibility report for this game.
  • [x] that I have checked whether there are updates for my system available.

Proton Log: steam-2183900.log.gz

Symptoms

Hello,
a new problem with this game has arisen for me. Up until about 2 weeks ago, I could play the game as usual. When I tried to play again yesterday, I couldn't reach the main menu anymore. The game starts, the "intro" videos play, shaders are precreating when cleaned, then the game will hang anytime before reaching the main menu. The "send report" dialog then appears after some time and the game exits upon answering the dialog box.

The driver error: "kernel: NVRM: Xid (PCI:0000:0c:00): 13, pid=2704, name=Warhammer 40000, Graphics Exception: channel 0x0000000b, Class 0000c997, Offset 00000000, Data 00000000", meaning that a GPU shader or compute kernel triggered an exception during execution.

Verifying files shows no error.
As the last successful game session was using previous NVIDIA driver version, I tried downgrading nvidia packages to last known good (595.71.05), cleaning shader caches and vkd3d-proton.cache files and rebooting, to no avail, same error.
I also tried the pyroveil route to counter some potentially problematic shaders, same error.

What was updated since last known good:

  • Proton experimental
  • Nvidia drivers
  • The game itself

Reproduction

Run the game, and have the game crash anywhere near intro cinematics and main menu (instant depends if you skip videos or not).

DDennisNeu 2026-06-05 github

The driver error: "kernel: NVRM: Xid (PCI:0000:0c:00): 13, pid=2704, name=Warhammer 40000, Graphics Exception: channel 0x0000000b, Class 0000c997, Offset 00000000, Data 00000000", meaning that a GPU shader or compute kernel triggered an exception during execution.

I had the same issue. Using these launch options (4k monitor)
gamescope -W 3840 -H 2160 -f -- %command%

and Proton Experimental got me into the main menu

BBillKills974 2026-06-08 github

I had the same issue. Using these launch options (4k monitor) gamescope -W 3840 -H 2160 -f -- %command%

and Proton Experimental got me into the main menu

No joy for me :(, same crash with gamescope.

BBillKills974 2026-06-09 github

After some tries, it seems the game does not crash if I set the game refresh rate to 60Hz or 90Hz:

  • A try with gamescope -W 3840 -H 2160 -r 60 -f -- %command% has let me reach past the crashing point.
  • Tries with -r 120 or -r 240, --adaptive-sync or not crashed every time.
  • While in the game, I limited the game fps to 60 and tried without gamescope or any launch option (as before the crashes appeared): now the game works.
  • I then tried 90 FPS, works too.
  • Upping the FPS limit to 120 in the menu = insta-crash (NVRM xid 13)
  • Reverted the FPS limit in the game settings using gamescope -W 3840 -H 2160 -r 90 -f -- %command% then removing the launch options: game works again.
  • I did multiple rounds of the same loop to "ensure" it's not pure luck: same crashes and fixes every time.

So if you encounter the same bug: FPS limit to 90 may help.

Aakappakappa 2026-07-16 github

Game has frame pacing issues on Intel hybrid CPUs.
Easily testable in-game in the hangar lobby, panning visual left-right.

I solved it on my setup using taskset to restrict it on P-Cores only.
taskset -c $(cat /sys/devices/cpu_core/cpus) %command%
Can this be integrated in Proton itself?
ty in advance

i7-13700K
RTX 4070 Ti
Proton Experimental

SSev501 2026-07-20 github

Replying to https://github.com/ValveSoftware/Proton/issues/8072#issuecomment-4595147633

I have encountered the same deal. I was able to play a few days ago and today I could not reach the main menu, when I press enter it crashes.

RTX 3080 / R7 5700x3D / CachyOS

I was able to get in by using this launch option.

VKD3D_CONFIG=descriptor_heap PROTON_VKD3D_HEAP=1

MMrAdrianPl 2026-07-22 github

Hi

I've found quite interesting issue with the game i need to fully confirm this with more testing but on my end no matter the proton version game freeze at every even hour. I'm not quite sure what reason might be and is it just my configuration related, maybe its new mesa version that my os got like a week ago, or something related with proton.

I'm looking for some guesses/ideas what this might be.

my specs:
Operating System: PikaOS 4
KDE Plasma Version: 6.5.4
KDE Frameworks Version: 6.20.0
Qt Version: 6.9.2
Kernel Version: 7.1.4-pikaos (64-bit)
Graphics Platform: Wayland
Processors: 16 × AMD Ryzen 7 5700G with Radeon Graphics
Memory: 32 GiB of RAM (30.7 GiB usable)
Graphics Processor 1: AMD Radeon RX 6700
Graphics Processor 2: AMD Radeon Graphics

thanks for any response in advance.

edit:
I've tested whether this might be somehow related to some service since it was weird that freeze always happened at even hours, but it's not related to any service i wonder whether its not something related to EAC runtime, but I'm not sure

Kkisak-valve maintainer 2026-07-31 github

Space Marine 2 crash mid-mission

Issue transferred from https://github.com/ValveSoftware/Proton/issues/10020.
@Ferrum115 posted on 2026-07-31T08:01:40:

Compatibility Report

  • Name of the game with compatibility issues: Warhammer 40,000: Space Marine 2
  • Steam AppID of the game: 2183900

System Information

I confirm:

  • [ ] that I haven't found an existing compatibility report for this game. (completely different problem + old[like, 2024 old])
  • [x] that I have checked whether there are updates for my system available.

Proton log (I closed the game manually before the crash):
proton-log-2183900.zip

Symptoms:

Mid-mission game throws crash message, then freezes until being closed manually. No freezes/lags/multiplayer desync/graphical artifacts before, just crash window out of the blue. Character is controllable around a minute after, then the game freezes.

Reproduction

  1. Install CachyOS latest with hyprland
  2. Run Warhammre 40,000: Space Marine 2
  3. Enter any multiplayer lobby
  4. Play the mission(s, you can complete multiple missions before the crash, but the fastest way to replicate is Siege mode)
  5. Wait until the crash window, looks like this:
    Image
FFerrum115 2026-07-31 github

steam-2183900-updated.zip
Updated proton log file, now containing freeze moment

Bbushibot 2026-08-25 github

Adding concrete evidence tying the periodic EAC main-thread stalls (previously tracked separately at #9379, merged here) to a specific, easily-measurable symptom: the controller goes completely dead during each stall, not just mouse/keyboard as reported before.

System: Bazzite (Fedora Atomic) desktop, kernel 7.2.0-ogc4.1.fc44.x86_64, AMD GPU (RADV), Proton-GE (latest), Steam Controller (Valve's own wireless "Puck" dongle, not a third-party pad).

Symptom: Mid-session, all controller input to the game stops entirely - only the Steam-button chord (handled by the Steam client itself, outside the game's input path) still works, confirming it's not a physical disconnect. Also hit a crash on exiting a level (matches earlier reports here from 2024 of crash-on-quit).

Concrete evidence of periodicity, pulled directly from the kernel log during one session:

$ journalctl -k --since "22:05:00" | grep "X-Box 360 pad"
Aug 24 22:05:39 kernel: input: Microsoft X-Box 360 pad 0 as /devices/virtual/input/input71
Aug 24 22:07:36 kernel: input: Microsoft X-Box 360 pad 0 as /devices/virtual/input/input72
Aug 24 22:07:42 kernel: input: Microsoft X-Box 360 pad 0 as /devices/virtual/input/input73
Aug 24 22:09:48 kernel: input: Microsoft X-Box 360 pad 0 as /devices/virtual/input/input74
Aug 24 22:11:51 kernel: input: Microsoft X-Box 360 pad 0 as /devices/virtual/input/input75
Aug 24 22:12:54 kernel: input: Microsoft X-Box 360 pad 0 as /devices/virtual/input/input76
Aug 24 22:14:14 kernel: input: Microsoft X-Box 360 pad 0 as /devices/virtual/input/input77
Aug 24 22:16:10 kernel: input: Microsoft X-Box 360 pad 0 as /devices/virtual/input/input78
Aug 24 22:16:21 kernel: input: Microsoft X-Box 360 pad 0 as /devices/virtual/input/input79
Aug 24 22:17:21 kernel: input: Microsoft X-Box 360 pad 0 as /devices/virtual/input/input80
Aug 24 22:17:45 kernel: input: Microsoft X-Box 360 pad 0 as /devices/virtual/input/input81
Aug 24 22:18:21 kernel: input: Microsoft X-Box 360 pad 0 as /devices/virtual/input/input82

That's Steam Input's virtual XInput device (uinput) being torn down and rebuilt roughly every 60-90 seconds, continuously, for the whole session - lining up closely with the "~30s to 2min" stall interval reported at #9379. My read: Steam Input is reactively rebuilding its virtual controller device each time it perceives the game/its input path as unresponsive during an EAC stall, which is why the controller (not just mouse/keyboard) goes fully dead each time.

Tried the usual Steam Input remedies first (forcing an Xbox-360-emulating controller layout instead of the native template) - confirmed via ~/.local/share/Steam/logs/controller.txt that this had zero effect on the underlying churn, so this isn't a per-game Steam Input config issue, it's downstream of the EAC stall itself.

Happy to grab a PROTON_LOG=1 capture or anything else useful if it'd help narrow this down further.

Bbushibot 2026-08-25 github

Correction to my comment above: I connected the controller churn to the EAC periodic-stall pattern based on a rough timing match, but further testing shows that's likely wrong. During the same kind of session, the game itself (framerate, rendering) ran smoothly the whole time with no stutter or freeze - only the controller went unresponsive, repeatedly. That doesn't match the "everything stalls together" symptom described for the EAC main-thread-stall issue, so I don't think these are the same bug. Apologies for the noise - leaving the kernel-log evidence above since the churn itself is still real and reproducible, just not (as far as I can tell) tied to the EAC stall specifically.

Kkisak-valve maintainer 2026-08-29 github

WH40K - Space Marine 2 Anti-Cheat Issue

Issue transferred from https://github.com/ValveSoftware/SteamOS/issues/2765.
@cptcruisectrl-ops posted on 2026-08-29T19:36:04:

Your system information

  • Steam client version:1787790984
  • SteamOS version: 3.9.0
  • Opted into Steam client beta?: [Yes/No] Yes - Preview
  • Opted into SteamOS beta?: [Yes/No] Yes
  • Have you checked for updates in Settings > System?: [Yes/No] Yes

Please describe your issue in as much detail as possible:

Describe what you expected should happen and what did happen.

Ran Space Marine 2 on Proton Experimental on 3.8.26. Anti-cheat worked fine. Running on 3.9.0 gives an error - Launch Error: Unexpected error (#1). Switched to Proton 11.0-2 and works fine. Just seems to be a problem with Proton Experimental.

Steps for reproducing this issue:

  1. Run under Proton Experimental
  2. Run under SteamOS 3.9.0
Kkisak-valve maintainer 2026-09-01 github

Easy Anti-Cheat launch failure on Proton Experimental/Hotfix (Unexpected error. (#1)) & Patch 14.1 Texture Streaming Crash

Issue transferred from https://github.com/ValveSoftware/Proton/issues/10111.
@Esenych posted on 2026-09-01T14:08:52:

Compatibility Report

  • Name of the game with compatibility issues: Warhammer 40,000: Space Marine 2
  • Steam AppID of the game: 2183900

System Information

  • GPU: NVIDIA GeForce RTX 3060 12GB LHR
  • Video driver version: NVIDIA 595.91.07
  • Kernel version: 7.2.0 (Nobara Linux, Wayland session)
  • Link to full system information report as Gist:
  • Proton version: Proton Experimental, Proton Hotfix, GE-Proton 11-5

I confirm:

  • [x] that I have checked whether there are updates for my system available.

Symptoms

There are two major issues:

  1. Launch failure on Proton Experimental & Proton Hotfix:
    The game fails to launch entirely when using official Proton Experimental or Proton Hotfix. Easy Anti-Cheat halts initialization with the popup error:

    "Ошибка запуска: Unexpected error. (#1)"
    The game currently only bypasses EAC and starts when using GE-Proton 11-5.

  2. Texture Streaming pool overflow / Crash on Patch 14.1 (GE-Proton 11-5):
    After 190+ hours of stable gameplay prior to Patch 14.1, reproducible crashes occur during extended play sessions (e.g. Operations / hm_fortress map). The engine triggers an unhandled exception / Crash Dump Sending Utility because the Texture Streaming allocator exceeds its assigned budget without triggering mipmap drops/eviction (0.0 mips drop).

Memory dump state at exception:
Title memory: 5887.6 / 11360.1 MB (3074.4 MB free)
GeomStreaming: 544.3 / 550.0 MB [Utilization: ~98.9%]
TexStreaming: 2065.3 / 2000.0 MB [OVERFLOW: +65.3 MB, 0.0 mips drop]
Reserved memory: 300.0 MB, 0.0 temp [MB]
Total Memory: 8168714240 bytes (~7.6 GB budget reported under Wine DXGI)
Free Host Memory: 26723504128 bytes (~24.8 GB)

Technical breakdown:

  • Wine DXGI reports total available memory as 8168714240 bytes (~7.6 GB) on a 12 GB physical GPU, causing the game to set a tight 2000 MB limit for TexStreaming.
  • During wave rotations, TexStreaming exceeds this hard cap (reaching 2065.3 MB), but GC/eviction fails (0.0 mips drop), leading to an immediate Access Violation crash.

Reproduction

For EAC Launch Error:

  1. Set game compatibility tool to Proton Experimental or Proton Hotfix.
  2. Launch Warhammer 40,000: Space Marine 2 from Steam.
  3. Observe EAC splash screen failing immediately with Unexpected error. (#1).

For Streaming Pool Crash (GE-Proton 11-5):

  1. Launch the game using GE-Proton 11-5.
  2. Start an Operations mission (e.g. hm_fortress / Decapitation).
  3. Play through extended enemy wave rotations.
  4. Observe process freeze and Crash Dump utility trigger when TexStreaming exceeds 2000 MB.
LLegion495 2026-09-03 github

Replying to https://github.com/ValveSoftware/Proton/issues/8072#issuecomment-5142885754

Basically the same for me.

Space Marine 2 crash mid-mission

System Information

* GPU: AMD Radeon RX 7900 XTX [Discrete]
* Video driver version: Mesa 26.2.1-arch3.1
* Kernel version: Linux 7.2.2-1-cachyos
* Proton version: Proton 11, proton-cachyos-11.0-20260703, GE-11-5_x86

What I noticed is that when I disable FSR I get the weirdest error.
The result is the same but the crash utility does not show up.
Instead I get an error like:
A crash report cannot be display because (repeats itself) - popup window and click OK and it dies.

I also seeing the memory overflow above. Despite having 24GB VRAM it still limits itself hard.

JJMarcosHP 2026-09-04 github

Replying to https://github.com/ValveSoftware/Proton/issues/8072#issuecomment-5142885754

My game crashes after every 30mins, I've tried with vanilla proton 11, Proton cachyOS latest, Proton GE 11.5 and 10.34, nothing stops this from crashing.

What's the workaround?

Vvladarias-spec 2026-09-04 github

Hi. Same problem here. For about a month now, it's suddenly started crashing mid-operation or near the end, before displaying the error message. I've tried Proton 9, experimental, and -GE, after deleting shaders at 2183900 first, and the same error always occurs.
system
Bazzite (KDE)
gpu:Radeon RX 9060 XT
cpu: ryzen 7 5700x

detalle completo
https://paste.centos.org/view/7f30a908

The log file is large (70MB), but this line seems to indicate the problem itself:

steam-2183900.zip

2513.719:00ec:00f0:trace:seh:dispatch_exception code=6ba (RPC_S_SERVER_UNAVAILABLE) flags=0 addr=00006FFFFFBFD947

Image
IIron-Warlock 2026-09-05 github

I am having the same issues with an unexpected side effect.
Kernel 7.2.2-1-cachyos-bore
gpu RX7800XT, mesa 26.2.2
Tried proton versions: ge-proton10-34, proton9.0-4, proton-cachyos-11.0-20260703 (steam linux runtime), proton11.0-2, ge-proton11-6-x86_64, proton experimental.

Some of these do not start at all (Unexpected error #1), otherwise the game starts and randomly during Operations I will get the "Application has stopped working" popup. But, the game itself keeps running if I ignore that, only 'freezing' when transitioning (from operation to victory/failure screen).

Neither dmesg/journalctl/PROTON_LOG=1 seem to capture anything relevant; I had some "Intense view map pressure! Got 1024 views in hash map ..." but, after disabling Frame Generation they seem to have disappeared.

UPDATE: ge-proton11-5-x86_64 seems to reduce the frequency of this happening, but the crash is now "full" - the game does not "keep running" as described earlier, but just freezes.

Kkisak-valve maintainer 2026-09-06 github

Warhammer 40,000: Space Marine 2 dont start

Issue transferred from https://github.com/ValveSoftware/Proton/issues/10122.
@thefilip988 posted on 2026-09-06T05:33:02:

Compatibility Report

  • Name of the game with compatibility issues: Warhammer 40,000: Space Marine
  • Steam AppID of the game: 2183900

System Information

I confirm:

  • [ *] that I haven't found an existing compatibility report for this game.
  • [ *] that I have checked whether there are updates for my system available.

steam-2183900.log
here the same in gist https://gist.github.com/thefilip988/cb32391e202946b0e1b3eae83740b29e

Symptoms

stuck on *--cwd' 'client_pcrootbinpc' and not start

Image

Reproduction

FFerrum115 2026-09-06 github

Kernel: Linux 7.2.2-1-cachyos
GPU: RTX 4080 Max-Q [mobile]
Proton version: proton-cachyos-11.0-20260703 (steam linux runtime)
"Continuation" on this issue: https://github.com/ValveSoftware/Proton/issues/8072#issuecomment-5142885754
Attempt at sending crash report and crash window, held on surprisingly long after crash message appeared. Third stage on Siege mode.
Image
Image

LLegion495 2026-09-06 github

The crashreport stays open until a new map section loads. Usually you will notice the loading zone (elevator) will have low resolution textures.

On steam the current suggestion is to clean out the shadercache of the game in the steam folder. Select Proton GE 11-5 (or default 11)and do not change any graphical setting after the new shader compilation.

I have yet to test longer. I was okay for 1 hour and about 30 minutes.

Ppa-oshea 2026-09-06 github

If anyone is looking for a workaround. This issue stopped for me when I downgraded my kernel from 7.2 to 7.1 on cachyos

JJMarcosHP 2026-09-06 github

If anyone is looking for a workaround. This issue stopped for me when I downgraded my kernel from 7.2 to 7.1 on cachyos

So, it's something with the new kernel version and an incorrect memory report from wine?

Ppa-oshea 2026-09-06 github

If anyone is looking for a workaround. This issue stopped for me when I downgraded my kernel from 7.2 to 7.1 on cachyos

So, it's something with the new kernel version and an incorrect memory report from wine?

I do not have enough knowledge in this area to be confident about what the issue is.
I worked through this with Claude: going through journalctl, coredumpctl, Proton logs, and eventually a kernel bisect.
Here is what Claude has to say about it:

"A reproducible EXCEPTION_ACCESS_VIOLATION at the same instruction address every time (0x14215902E), across multiple Proton versions (stock 11.0-2, Proton 10.x, and proton-cachyos), so it's not a Proton-specific bug. I also tested kernel 6.18.42 LTS and got the same crash there, so it's not simply "newer kernel = broken" — something specific changed between 7.1.8 and 7.2.0 that isn't present in either 7.1.8 or the LTS branch.
The crash address staying identical while the exception's secondary info value changes each time made us think it's more likely a timing/race condition (maybe ntsync or a scheduler change) than a straightforward bad memory report, but neither of us knows Wine/kernel internals well enough to confirm that. Been stable on 7.1.8 since."

JJMarcosHP 2026-09-07 github

Replying to https://github.com/ValveSoftware/Proton/issues/8072#issuecomment-5561397900

I downgraded my kernel to that version 7.1.8
I can confirm that this kernel has something else that prevents these crashes after playing 1 long siege match.

JJMarcosHP 2026-09-07 github

After 3hrs of heavy gameplay with 7.1.8, I got 0 crashes.

The workaround for now is to stick with 7.1.8, idk how this kernel manages to avoid these memory overflows with the texture streaming.

I only used proton-cachyos latest.

ZZeronthe 2026-09-07 github

Using stock proton 11.0-2 and 7.1.11-zen1-1-zen kernel also produces no crashes. Got crashes on latest cachy and garuda kernels, though.

I've always had similar issues like these on the cachy-like kernels though, which is why i went back to zen as soon as i crashed when i was trying out the garuda kernel for the first time. They Always seem to be more trouble than they're worth, at least for my configuration.

LLegion495 2026-09-07 github

If I could pursade you guys.
journalctl -b -p err after crash.

I did open a topic on https://discuss.cachyos.org/t/kernel-7-1-to-7-2-crashes-with-proton-space-marine-2/35399
Because it would be dandy to have this fixed asap. If I have the chance to experience a crash will do the same.

JJMarcosHP 2026-09-07 github

I think it's not specific to cachy's kernel, I tried it on openSUSE locking the 7.1.8 and it's the same result.

LLegion495 2026-09-07 github

I think it's not specific to cachy's kernel, I tried it on openSUSE locking the 7.1.8 and it's the same result.

Same result as in not crashing I assume?
I would still like to have some crash logs I could escalate to the devs on the forum and hopefully then get a fix for the next kernel or a patch.

JJMarcosHP 2026-09-07 github

I think it's not specific to cachy's kernel, I tried it on openSUSE locking the 7.1.8 and it's the same result.

Same result as in not crashing I assume?
I would still like to have some crash logs I could escalate to the devs on the forum and hopefully then get a fix for the next kernel or a patch.

Yes 0 crashes.

Ppa-oshea 2026-09-07 github

I think it's not specific to cachy's kernel, I tried it on openSUSE locking the 7.1.8 and it's the same result.

Same result as in not crashing I assume? I would still like to have some crash logs I could escalate to the devs on the forum and hopefully then get a fix for the next kernel or a patch.

Transparency note: this investigation was done with help from Claude via the browser chat interface. Claude had no access to my machine; I ran every command and pasted the output in. Its role was suggesting diagnostic steps, interpreting logs, and structuring this write-up.

@Legion495 Here's the journalctl -b -p err output you asked for. It's from a crash-loop on 2026-09-06, which happened on kernel 7.1.8 (the one I'd otherwise found stable), not on 7.2.0. Details on that below.

Sep 06 22:24:12 kernel: NVRM: GPU at PCI:0000:01:00: GPU-dc9ccec1-be76-2ac3-5938-b59e99f1242e
Sep 06 22:24:12 kernel: NVRM: Xid (PCI:0000:01:00): 13, pid=12770, name=Warhammer 40000, Graphics Exception: channel 0x00000009, Class 0000c997, Offset 00000000, Data 00000000
Sep 06 22:25:44 kernel: NVRM: Xid (PCI:0000:01:00): 13, pid=13692, name=Warhammer 40000, Graphics Exception: channel 0x0000000a, Class 0000c997, Offset 00000000, Data 00000000
Sep 06 22:27:32 kernel: NVRM: Xid (PCI:0000:01:00): 13, pid=14559, name=Warhammer 40000, Graphics Exception: channel 0x0000000a, Class 0000c997, Offset 00000000, Data 00000000
Sep 06 22:45:12 kernel: NVRM: GPU at PCI:0000:01:00: GPU-dc9ccec1-be76-2ac3-5938-b59e99f1242e
Sep 06 22:45:12 kernel: NVRM: Xid (PCI:0000:01:00): 13, pid=4979, name=Warhammer 40000, Graphics Exception: channel 0x00000007, Class 0000c997, Offset 00000000, Data 00000000
Sep 06 23:26:48 kernel: NVRM: Xid (PCI:0000:01:00): 13, pid=9928, name=Warhammer 40000, Graphics Exception: channel 0x00000007, Class 0000c997, Offset 00000000, Data 00000000
Sep 06 23:29:34 kernel: NVRM: Xid (PCI:0000:01:00): 13, pid=10835, name=Warhammer 40000, Graphics Exception: channel 0x00000029, Class 0000c997, Offset 00000000, Data 00000000
Sep 06 23:38:18 kernel: NVRM: Xid (PCI:0000:01:00): 13, pid=12816, name=Warhammer 40000, Graphics Exception: channel 0x00000007, Class 0000c997, Offset 00000000, Data 00000000
Sep 06 23:40:14 kernel: NVRM: Xid (PCI:0000:01:00): 13, pid=13739, name=Warhammer 40000, Graphics Exception: channel 0x00000007, Class 0000c997, Offset 00000000, Data 00000000
Sep 06 23:42:14 kernel: NVRM: Xid (PCI:0000:01:00): 13, pid=14730, name=Warhammer 40000, Graphics Exception: channel 0x00000007, Class 0000c997, Offset 00000000, Data 00000000
Sep 06 23:47:14 kernel: NVRM: Xid (PCI:0000:01:00): 13, pid=16061, name=Warhammer 40000, Graphics Exception: channel 0x00000008, Class 0000c997, Offset 00000000, Data 00000000
Sep 06 23:48:54 kernel: NVRM: Xid (PCI:0000:01:00): 13, pid=16938, name=Warhammer 40000, Graphics Exception: channel 0x00000008, Class 0000c997, Offset 00000000, Data 00000000

Xid 13 is a Graphics Engine Exception: the GPU rejected a command buffer containing an invalid instruction or illegal memory access. Class 0000c997 is the Ada 3D class, so the fault is on the graphics engine (vkd3d/DX12 submission), not compute or copy. It fired 12 times across ~85 minutes, each against a fresh game PID. The second GPU at PCI line at 22:45 is the driver reloading after a full PC restart. That matches what I was doing: relaunching repeatedly after the game crashed before reaching the main menu, both before and after the reboot.

I don't yet have -p err output from a crash on 7.2.0 or 6.18.42-LTS (my "always crashes" combo). I'll capture it next time and post it to the forum thread too. It'd be worth someone on a non-CachyOS distro grabbing the same output if they can reproduce.

Full investigation notes

System

  • CachyOS, KDE Plasma
  • Ryzen 7 7800X3D, 32 GB RAM, RTX 4070 SUPER
  • NVIDIA 610.57.04 open kernel module (linux-cachyos-nvidia-open, version-pinned to each kernel tested), CUDA UMD 13.3

Kernel / Proton matrix

Kernel Proton Result
linux-cachyos 7.2.0-1 11.0-2 stock Crashes (where this started, after a routine pacman -Syu)
7.2.0-1 proton-cachyos-11.0-20260703 Crashes before main menu (worse than stock)
7.2.0-1 10.x stock Crashes
linux-cachyos-lts 6.18.42-1 proton-cachyos-11.0-20260703 Crashes, same signature
6.18.42-1-lts 10.x stock Completed one Operation, degraded performance
7.1.8-1 (kernel + headers + nvidia-open from pacman cache) 11.0-1 stock (assumed, not recorded) Stable, fresh Wine prefix, long session at Ultra
7.1.8-1 proton-cachyos-11.0-20260703 Stable for ~2 weeks of sessions

@JMarcosHP's openSUSE result at 7.1.8 (no crashes) matches this, so it looks version-specific rather than CachyOS-specific. Unconfirmed: a Reddit comment reports crashes on 7.1.9 (Omarchy), which would make the safe window narrower than "7.1.x good, 7.2.x bad".

Crash signature (7.2.0 and LTS)

From PROTON_LOG=1:

trace:seh:dispatch_exception code=c0000005 (EXCEPTION_ACCESS_VIOLATION) flags=0 addr=<see below>

Followed by a second mscoree/.NET process (presumably EAC) throwing code=6be (RPC_S_CALL_FAILED) and code=6ba (RPC_S_SERVER_UNAVAILABLE), which I read as it losing its RPC peer after the game dies.

Build Fault address
7.2.0, Proton 11, original 0x14271AB2C
7.2.0, later session 0x14215902E (identical across 3 crashes)
After game patch 14.2 0x14271AAEC (64 bytes from the original, likely the same function)

Within one kernel/Proton/game build the address is identical across crashes while info[1] differs each time (0x0B, 0xFB, 0x23). Same instruction, different auxiliary data reads more like a race or use-after-free than a deterministic bug, but that's my interpretation without symbols.

Kernel logs (journalctl -k) were clean around these 7.2.0/LTS crashes: no Xid, no GPU reset.

The 2026-09-06 incident (7.1.8, the Xid 13 log above)

On the previously-stable 7.1.8 + proton-cachyos combination: a freeze mid-session (FPS locked at 57, didn't recover), then a crash-loop before the main menu that survived a full reboot. Switching to Proton 11.0-2 later that night fixed it immediately. Next day I switched back to proton-cachyos to reproduce and it ran clean.

Two things changed around then, neither confirmed causal:

  • A new monitor was connected shortly before the freeze. -p err also shows a kwin display-output-configuration failure at 22:28:20, right after the last Xid in the first boot.
  • The 14.2 hotfix shipped around the same time.

I want to be careful not to over-link this to the 7.2.0 crash. It presented differently (freeze, then loop), the 7.2.0 crashes had clean kernel logs, and I have no PROTON_LOG for this window (the log had grown past a million lines without rotation). It may be a separate failure mode, possibly display-topology related, rather than corroboration of the kernel-version issue.

Ruled out (7.2.0 / LTS crashes)

  • OOM: no OOM-killer activity
  • Thermal/hardware: nvidia-smi clocks and temps normal
  • Core dumps: none via systemd-coredump (consistent with an SEH exception inside Wine, not a raw SIGSEGV)
  • Game crash reporter: client/reports/error.yaml never generated
  • kernel.yama.ptrace_scope: at default 1, so not the EAC/ptrace issue
  • Wine prefix: reproduced after deleting compatdata/2183900
  • PROTON_ENABLE_NTSYNC=0: no effect on 7.2.0 (doesn't rule out sync-primitive behaviour more broadly, just this toggle)
  • Launch options / ratbagctl scripting: removed, no effect
  • DLSS / Frame Gen: disabling them lengthened time-to-crash but didn't stop it; a stressor, not the cause

Working theory

A race or use-after-free in the game whose trigger probability is shifted by kernel timing (scheduler, ntsync/futex) and GPU load. 7.1.8 makes it rare but not impossible, which would fit both the two-week stable run and one bad night. I can't reproduce the 09-06 incident on demand, which is the main gap here.

JJMarcosHP 2026-09-07 github

I'll try to give some output using 7.2.2 and 7.1.8 from openSUSE.

LLegion495 2026-09-07 · hidden on GitHub github

I am on 7.2.2-1 on Cachy Standard and I am currently crashfree and this confuses me at the moment.

LLegion495 2026-09-07 github
It crashed
> Sep 07 21:46:38 tribble systemd[1]: Starting Daily Cleanup of Snapper Snapshots...
> Sep 07 21:46:38 tribble systemd[1]: Started Daily Cleanup of Snapper Snapshots.
> Sep 07 21:46:38 tribble systemd[1]: Starting DBus interface for snapper...
> Sep 07 21:46:38 tribble systemd[1]: Started DBus interface for snapper.
> Sep 07 21:46:38 tribble systemd-helper[150328]: Running cleanup for 'root'.
> Sep 07 21:46:38 tribble systemd-helper[150328]: Running number cleanup for 'root'.
> Sep 07 21:46:38 tribble systemd-helper[150328]: Running timeline cleanup for 'root'.
> Sep 07 21:46:38 tribble systemd-helper[150328]: Running empty-pre-post cleanup for 'root'.
> Sep 07 21:46:39 tribble limine-snapper-sync[150355]: Snapshot limit mismatch: 50 Snapper snapshots exceed configured MAX_SNAPSHOT_ENTRIES=8
> Sep 07 21:46:39 tribble limine-snapper-sync[150367]: Snapshot limit mismatch: 50 Snapper snapshots exceed configured MAX_SNAPSHOT_ENTRIES=8
> Sep 07 21:46:39 tribble limine-snapper-sync[150355]: To remove this warning, increase MAX_SNAPSHOT_ENTRIES or lower the Snapper limit.
> Sep 07 21:46:39 tribble systemd[1]: snapper-cleanup.service: Deactivated successfully.
> Sep 07 21:46:45 tribble discord[142888]: 21:46:45.491 › [RTCControlSocket(default)] Sending heartbeat with last received sequence number: 14
> Sep 07 21:46:45 tribble discord[142888]: 21:46:45.521 › [RTCControlSocket(default)] Heartbeat ACK received
> Sep 07 21:46:55 tribble discord[142888]: 21:46:55.116 › [Connection(default)] updateVideoQuality: {"remoteSinkWantsMaxFramerate":30}
> Sep 07 21:46:59 tribble discord[142888]: 21:46:59.242 › [RTCControlSocket(default)] Sending heartbeat with last received sequence number: 14
> Sep 07 21:46:59 tribble discord[142888]: 21:46:59.271 › [RTCControlSocket(default)] Heartbeat ACK received
> Sep 07 21:47:12 tribble discord[142888]: 21:47:12.992 › [RTCControlSocket(default)] Sending heartbeat with last received sequence number: 14
> Sep 07 21:47:13 tribble discord[142888]: 21:47:13.025 › [RTCControlSocket(default)] Heartbeat ACK received
> Sep 07 21:47:26 tribble discord[142888]: 21:47:26.741 › [RTCControlSocket(default)] Sending heartbeat with last received sequence number: 14
> Sep 07 21:47:26 tribble discord[142888]: 21:47:26.775 › [RTCControlSocket(default)] Heartbeat ACK received
> Sep 07 21:47:39 tribble systemd[1]: snapperd.service: Deactivated successfully.
> Sep 07 21:47:40 tribble discord[142888]: 21:47:40.492 › [RTCControlSocket(default)] Sending heartbeat with last received sequence number: 14
> Sep 07 21:47:40 tribble discord[142888]: 21:47:40.521 › [RTCControlSocket(default)] Heartbeat ACK received
> Sep 07 21:47:46 tribble steam[77600]: src/steamUI/controllerconfig.h (146) : Assertion Failed: CPrepareConfigWorker failed for AppID 413080
> Sep 07 21:47:46 tribble steam[77600]: src/steamUI/controllerconfig.h (146) : Assertion Failed: CPrepareConfigWorker failed for AppID 413080
> Sep 07 21:47:46 tribble systemd[1332]: Started Alacritty - Terminal.
> Sep 07 21:47:48 tribble discord[142888]: 21:47:48.151 › [RunningGameStore] Running Games Changed [object Object]
> Sep 07 21:47:48 tribble discord[142888]: 21:47:48.155 › [RunningGameStore] Running Non-Games Changed [object Object]
> Sep 07 21:47:48 tribble discord[142888]: 21:47:48.157 › [OverlayBridgeStore] updateIntendedOverlayPIDs [object Object]
> Sep 07 21:47:48 tribble discord[142888]: 21:47:48.157 › [OverlayBridgeStore] updateIntendedOverlayPIDs [object Object]
> Sep 07 21:47:48 tribble discord[142888]: 21:47:48.157 › [OverlayBridgeStore] updateIntendedOverlayPIDs: Removing all. [object Object] [object Object]
> Sep 07 21:47:48 tribble discord[142888]: 21:47:48.158 › [Clips] decider: handleRunningGamesChange visibleGame=Warhammer 40,000: Space Marine II newPrimaryKey=s:/steamapps/common/space marine 2/client_pc/root/bin/pc/warhammer 40000 s>
> Sep 07 21:47:48 tribble discord[142888]: 21:47:48.158 › [Clips] decider: handleRunningGamesChange — same primary, cancelling pending end
> Sep 07 21:47:54 tribble discord[142888]: 21:47:54.242 › [RTCControlSocket(default)] Sending heartbeat with last received sequence number: 14
> Sep 07 21:47:54 tribble discord[142888]: 21:47:54.271 › [RTCControlSocket(default)] Heartbeat ACK received
> Sep 07 21:48:00 tribble discord[142888]: 21:48:00.203 › [ConnectionEventFramerateReducer] BaseConnection.userSpeakingChange: Reduced framerate after 15000 ms.
> Sep 07 21:48:00 tribble discord[142888]: 21:48:00.203 › [Connection(default)] updateVideoQuality: {"remoteSinkWantsMaxFramerate":20}
> Sep 07 21:48:03 tribble steam[77600]: src/steamUI/controllerconfig.h (146) : Assertion Failed: CPrepareConfigWorker failed for AppID 413080
> Sep 07 21:48:03 tribble steam[77600]: src/steamUI/controllerconfig.h (146) : Assertion Failed: CPrepareConfigWorker failed for AppID 413080
> Sep 07 21:48:07 tribble steam[77600]: src/steamUI/controllerconfig.h (146) : Assertion Failed: CPrepareConfigWorker failed for AppID 413080
> Sep 07 21:48:07 tribble steam[77600]: src/steamUI/controllerconfig.h (146) : Assertion Failed: CPrepareConfigWorker failed for AppID 413080
> Sep 07 21:48:07 tribble discord[142888]: 21:48:07.992 › [RTCControlSocket(default)] Sending heartbeat with last received sequence number: 14
> Sep 07 21:48:08 tribble discord[142888]: 21:48:08.035 › [RTCControlSocket(default)] Heartbeat ACK received
> Sep 07 21:48:13 tribble discord[142888]: 21:48:13.166 › [RunningGameStore] Running Games Changed [object Object]
> Sep 07 21:48:13 tribble discord[142888]: 21:48:13.171 › [RunningGameStore] Running Non-Games Changed [object Object]
> Sep 07 21:48:13 tribble discord[142888]: 21:48:13.172 › [OverlayBridgeStore] updateIntendedOverlayPIDs [object Object]
> Sep 07 21:48:13 tribble discord[142888]: 21:48:13.172 › [OverlayBridgeStore] updateIntendedOverlayPIDs [object Object]
> Sep 07 21:48:13 tribble discord[142888]: 21:48:13.172 › [OverlayBridgeStore] updateIntendedOverlayPIDs: Removing all. [object Object] [object Object]
> Sep 07 21:48:13 tribble discord[142888]: 21:48:13.173 › [Clips] decider: handleRunningGamesChange visibleGame=Warhammer 40,000: Space Marine II newPrimaryKey=s:/steamapps/common/space marine 2/client_pc/root/bin/pc/warhammer 40000 s>
> Sep 07 21:48:13 tribble discord[142888]: 21:48:13.173 › [Clips] decider: handleRunningGamesChange — same primary, cancelling pending end
> Sep 07 21:48:15 tribble discord[142888]: 21:48:15.460 › [Connection(default)] updateVideoQuality: {"remoteSinkWantsMaxFramerate":30}
> Sep 07 21:48:16 tribble spectacle[74270]: QQmlComponent: Cannot create a component in an invalid context
> Sep 07 21:48:16 tribble spectacle[74270]: QQmlComponent: Cannot create a component in an invalid context
> Sep 07 21:48:22 tribble discord[142888]: 21:48:22.116 › [RTCControlSocket(default)] Sending heartbeat with last received sequence number: 14
> Sep 07 21:48:22 tribble discord[142888]: 21:48:22.145 › [RTCControlSocket(default)] Heartbeat ACK received
> Sep 07 21:48:24 tribble steam[77600]: pid 143862 != 143861, skipping destruction (fork without exec?)
> Sep 07 21:48:24 tribble steam[77600]: Game Recording - game stopped [gameid=2183900]
> Sep 07 21:48:24 tribble steam[77600]: Removing process 144013 for gameID 2183900
> Sep 07 21:48:24 tribble steam[77600]: Removing process 143996 for gameID 2183900
> Sep 07 21:48:24 tribble steam[77600]: Removing process 143962 for gameID 2183900
> Sep 07 21:48:24 tribble steam[77600]: Removing process 143955 for gameID 2183900
> Sep 07 21:48:24 tribble steam[77600]: Removing process 143953 for gameID 2183900
> Sep 07 21:48:24 tribble steam[77600]: Removing process 143943 for gameID 2183900
> Sep 07 21:48:24 tribble steam[77600]: Removing process 143898 for gameID 2183900
> Sep 07 21:48:24 tribble steam[77600]: Removing process 143884 for gameID 2183900
> Sep 07 21:48:24 tribble steam[77600]: Removing process 143879 for gameID 2183900
> Sep 07 21:48:24 tribble steam[77600]: Removing process 143869 for gameID 2183900
> Sep 07 21:48:24 tribble steam[77600]: Removing process 143866 for gameID 2183900
> Sep 07 21:48:24 tribble steam[77600]: Removing process 143864 for gameID 2183900
> Sep 07 21:48:24 tribble steam[77600]: Removing process 143861 for gameID 2183900
> Sep 07 21:48:24 tribble steam[77600]: Removing process 143860 for gameID 2183900
> Sep 07 21:48:24 tribble steam[77600]: Removing process 143859 for gameID 2183900
> Sep 07 21:48:24 tribble steam[77600]: Removing process 143854 for gameID 2183900
> Sep 07 21:48:24 tribble steam[77600]: Removing process 143759 for gameID 2183900
> Sep 07 21:48:24 tribble steam[77600]: Removing process 143758 for gameID 2183900
> Sep 07 21:48:24 tribble steam[77600]: Removing process 143757 for gameID 2183900
> Sep 07 21:48:24 tribble steam[77600]: Removing process 143752 for gameID 2183900
> Sep 07 21:48:24 tribble steam[77600]: Removing process 143745 for gameID 2183900
> Sep 07 21:48:24 tribble steam[77600]: Removing process 143744 for gameID 2183900
> Sep 07 21:48:24 tribble steam[77600]: Removing process 143742 for gameID 2183900
> Sep 07 21:48:24 tribble steam[77600]: Removing process 143740 for gameID 2183900
> Sep 07 21:48:24 tribble steam[77600]: Removing process 143737 for gameID 2183900
> Sep 07 21:48:25 tribble steam[77600]: src/steamUI/controllerconfig.h (146) : Assertion Failed: CPrepareConfigWorker failed for AppID 413080
> Sep 07 21:48:25 tribble steam[77600]: src/steamUI/controllerconfig.h (146) : Assertion Failed: CPrepareConfigWorker failed for AppID 413080
> Sep 07 21:48:28 tribble discord[142888]: 21:48:28.148 › [RunningGameStore] Running Games Changed [object Object]
> Sep 07 21:48:28 tribble discord[142888]: 21:48:28.151 › [RunningGameStore] Running Non-Games Changed [object Object]
> Sep 07 21:48:28 tribble discord[142888]: 21:48:28.152 › [OverlayBridgeStore] updateIntendedOverlayPIDs [object Object]
> Sep 07 21:48:28 tribble discord[142888]: 21:48:28.152 › [OverlayBridgeStore] updateIntendedOverlayPIDs [object Object]
> Sep 07 21:48:28 tribble discord[142888]: 21:48:28.152 › [OverlayBridgeStore] updateIntendedOverlayPIDs: Removing all. [object Object] [object Object]
> Sep 07 21:48:28 tribble discord[142888]: 21:48:28.152 › [Clips] decider: handleRunningGamesChange visibleGame=null newPrimaryKey=null currentSessionGameKey=s:/steamapps/common/space marine 2/client_pc/root/bin/pc/warhammer 40000 spa>
> Sep 07 21:48:28 tribble discord[142888]: 21:48:28.152 › [Clips] decider: handleRunningGamesChange — visible game became null, finalizing session immediately
> Sep 07 21:48:28 tribble discord[142888]: 21:48:28.152 › [Clips] decider: processClipCandidates — sessionId=3f0aecee-9065-44b7-a936-ab6b40f0c264 candidates=0 staleCandidates=0 autoStashEnabled=false
> Sep 07 21:48:28 tribble discord[142888]: 21:48:28.153 › [Clips] ranked clips: [object Object]
> Sep 07 21:48:35 tribble steam[77600]: reaping pid: 144543 -- gameoverlayui
> Sep 07 21:48:36 tribble discord[142888]: 21:48:36.116 › [RTCControlSocket(default)] Sending heartbeat with last received sequence number: 14
> Sep 07 21:48:36 tribble discord[142888]: 21:48:36.146 › [RTCControlSocket(default)] Heartbeat ACK received
> Sep 07 21:48:41 tribble discord[142888]: 21:48:41.116 › [ConnectionEventFramerateReducer] BaseConnection.userSpeakingChange: Reduced framerate after 15000 ms.
> Sep 07 21:48:41 tribble discord[142888]: 21:48:41.116 › [Connection(default)] updateVideoQuality: {"remoteSinkWantsMaxFramerate":20}
> Sep 07 21:48:44 tribble discord[142888]: 21:48:44.116 › [WindowVisibilityVideoManager] Incoming video enabled changed, incomingVideoEnabled = false
> Sep 07 21:48:50 tribble discord[142888]: 21:48:50.116 › [RTCControlSocket(default)] Sending heartbeat with last received sequence number: 14
> Sep 07 21:48:50 tribble discord[142888]: 21:48:50.145 › [RTCControlSocket(default)] Heartbeat ACK received
> Sep 07 21:49:03 tribble discord[142888]: 21:49:03.116 › [RTCControlSocket(default)] Sending heartbeat with last received sequence number: 14
> Sep 07 21:49:03 tribble discord[142888]: 21:49:03.146 › [RTCControlSocket(default)] Heartbeat ACK received
> Sep 07 21:49:17 tribble discord[142888]: 21:49:17.116 › [RTCControlSocket(default)] Sending heartbeat with last received sequence number: 14
> Sep 07 21:49:17 tribble discord[142888]: 21:49:17.145 › [RTCControlSocket(default)] Heartbeat ACK received
> Sep 07 21:49:31 tribble discord[142888]: 21:49:31.116 › [RTCControlSocket(default)] Sending heartbeat with last received sequence number: 14
> Sep 07 21:49:31 tribble discord[142888]: 21:49:31.143 › [RTCControlSocket(default)] Heartbeat ACK received
> Sep 07 21:49:45 tribble discord[142888]: 21:49:45.116 › [RTCControlSocket(default)] Sending heartbeat with last received sequence number: 14
> Sep 07 21:49:45 tribble discord[142888]: 21:49:45.145 › [RTCControlSocket(default)] Heartbeat ACK received
> Sep 07 21:49:58 tribble discord[142888]: 21:49:58.116 › [RTCControlSocket(default)] Sending heartbeat with last received sequence number: 14
> Sep 07 21:49:58 tribble discord[142888]: 21:49:58.144 › [RTCControlSocket(default)] Heartbeat ACK received
> Sep 07 21:50:12 tribble discord[142888]: 21:50:12.116 › [RTCControlSocket(default)] Sending heartbeat with last received sequence number: 14
> Sep 07 21:50:12 tribble discord[142888]: 21:50:12.143 › [RTCControlSocket(default)] Heartbeat ACK received
> Sep 07 21:50:26 tribble discord[142888]: 21:50:26.116 › [RTCControlSocket(default)] Sending heartbeat with last received sequence number: 14
> Sep 07 21:50:26 tribble discord[142888]: 21:50:26.144 › [RTCControlSocket(default)] Heartbeat ACK received
> Sep 07 21:50:40 tribble discord[142888]: 21:50:40.116 › [RTCControlSocket(default)] Sending heartbeat with last received sequence number: 14
> Sep 07 21:50:40 tribble discord[142888]: 21:50:40.144 › [RTCControlSocket(default)] Heartbeat ACK received

Ppa-oshea 2026-09-07 github

Tested linux-cachyos-bore kernel 7.2.3 and still crashed. Wanted to test out since cachyos readme suggests the bore kernel for gaming.

journalctl -b -p err for this boot is clean: no Xid, no kernel-level fault of any kind.

Sep 07 23:36:59 cachyos kernel: virt/tdx: TDX not supported by the host platform
Sep 07 23:37:05 Atlas wpa_supplicant[966]: wlan0: nl80211: kernel reports: multicast RX registrations are not supported
Sep 07 23:37:07 Atlas libvirtd[971]: cannot open directory '/var/lib/libvirt/images/pool': No such file or directory
Sep 07 23:37:18 Atlas org_kde_powerdevil[1675]: [  1675][  1.627494] Time since library initialized:   1.627494 seconds

PROTON_LOG=1 shows the same signature as before. This time I have the full exception and backtrace:

Exception, registers, and backtrace (thread 01b4)
2044.270:01a0:01b4:trace:seh:dispatch_exception code=c0000005 (EXCEPTION_ACCESS_VIOLATION) flags=0 addr=0000000142158FEE
2044.270:01a0:01b4:trace:seh:dispatch_exception  info[0]=0000000000000000
2044.270:01a0:01b4:trace:seh:dispatch_exception  info[1]=000000000000000B
2044.270:01a0:01b4:trace:seh:dispatch_exception rip=0000000142158fee rsp=00000000197bfc48 rbp=0000000142159040 eflags=00010246
2044.270:01a0:01b4:trace:seh:dispatch_exception rax=0000000000000000 rbx=000000010d44ebc0 rcx=0000000000000003 rdx=0000000000000000
2044.270:01a0:01b4:trace:seh:dispatch_exception rsi=0000000340e68640 rdi=0000000340e68600  r8=000000010d44eba0  r9=00006ffffffa77e0
2044.270:01a0:01b4:trace:seh:dispatch_exception r10=00006ffffc530000 r11=000000002f451c70 r12=0000000000000000 r13=00000000081a4000
2044.270:01a0:01b4:trace:seh:dispatch_exception r14=000000017eb08fd8 r15=00000000197bfce0 mxcsr=00001f80 cs=0033 ss=002b
2044.270:01a0:01b4:warn:seh:virtual_unwind backtrace: 0000000142158FEE: L"Warhammer 40000 Space Marine 2 - Retail.exe" + 0000000002158FEE.
2044.270:01a0:01b4:warn:seh:virtual_unwind backtrace: 0000000142175F8E: L"Warhammer 40000 Space Marine 2 - Retail.exe" + 0000000002175F8E.
2044.270:01a0:01b4:warn:seh:virtual_unwind backtrace: 00000001421590AA: L"Warhammer 40000 Space Marine 2 - Retail.exe" + 00000000021590AA.
2044.270:01a0:01b4:warn:seh:virtual_unwind backtrace: 0000000142658DCD: L"Warhammer 40000 Space Marine 2 - Retail.exe" + 0000000002658DCD.
2044.270:01a0:01b4:warn:seh:virtual_unwind backtrace: 00000001426AC595: L"Warhammer 40000 Space Marine 2 - Retail.exe" + 00000000026AC595.
2044.270:01a0:01b4:warn:seh:virtual_unwind backtrace: 00000001426DB7A9: L"Warhammer 40000 Space Marine 2 - Retail.exe" + 00000000026DB7A9.
2044.270:01a0:01b4:warn:seh:virtual_unwind backtrace: 00000001426DA4F4: L"Warhammer 40000 Space Marine 2 - Retail.exe" + 00000000026DA4F4.
2044.270:01a0:01b4:warn:seh:virtual_unwind backtrace: 0000000142726CF9: L"Warhammer 40000 Space Marine 2 - Retail.exe" + 0000000002726CF9.
2044.270:01a0:01b4:warn:seh:virtual_unwind backtrace: 00006FFFFFEC1649: L"kernel32.dll" + 0000000000011649.
2044.270:01a0:01b4:warn:seh:virtual_unwind backtrace: 00006FFFFFF40E0F: L"ntdll.dll" + 0000000000010E0F.

(Claude)
What this shows:

  • info[0]=0, info[1]=0xB: a read from address 0xB, i.e. a null pointer dereference at a small field offset. rax, rdx and r12 are all zero at the fault. The earlier crashes had info[1] of 0x0B, 0xFB and 0x23, so every capture is a near-null read on the same instruction, never a random heap address. That points at a missing null check on something that comes back empty under certain timing (a lookup, a not-yet-ready resource, an already-released handle), rather than heap corruption.
  • The faulting address is 64 bytes from the one in my second 7.2.0 session (0x14215902E), so the same function for all practical purposes. 0x142158FEE is a small leaf helper with no stack frame, called from 0x142175F8E.
  • The whole stack is in Retail.exe, from the crash down to the kernel32/ntdll thread start. No EAC, Proton, or Nvidia Streamline module (DLSS, DLSS-G, Reflex, DeepDVC) is on it. It's a worker thread the engine created itself (01b4, a low thread ID created right after the main thread), dying about 11 minutes into the session.

Versions for this run: stock Proton 11.0-2 (proton-11.0-2c+ per DXVK-NVAPI), DXVK v2.7.1-498-ga6764047e587178, vkd3d-proton build 212991fc2c266bc.

So the crash has now reproduced across:

  • Kernels 7.2.0, 7.2.2, and 7.2.3 (BORE)
  • Proton 10.x, stock 11.0-2, and proton-cachyos
  • Before and after the game's 14.2 hotfix

Only 7.1.8 has been consistently stable for me, with the one exception. Given this is a null read in CPU code, that Xid 13 incident now looks like a separate failure mode rather than the same bug, since a GPU command-buffer fault wouldn't present this way.

My read is that the fix probably has to come from Saber: the fault is a null pointer de-reference on a worker thread in their own binary, and 7.1.8 most likely just shifts timing so the race is rarely lost, rather than fixing anything. But whatever changed between 7.1.8 and 7.2.0 is still worth identifying, since it may expose the same kind of latent race in other timing-sensitive games.
(Claude)

JJMarcosHP 2026-09-08 github

How do you get these logs? I tried launching Steam from the command line and then playing Space Marine, but after the crash, the output doesn't contain any relevant logs.

Same with journal.

I tried with 7.2.2, it crashes after 30 mins of gameplay.

Specs:

Operating System: openSUSE Tumbleweed 20260902
KDE Plasma Version: 6.7.4
KDE Frameworks Version: 6.29.0
Qt Version: 6.11.2
Kernel Version: 7.2.2-1-default (64-bit)
Graphics Platform: Wayland
Processors: 16 × AMD Ryzen 7 5700X 8-Core Processor
Memory: 32 GiB of RAM (31.3 GiB usable)
Graphics Processor: AMD Radeon RX 7600
Ppa-oshea 2026-09-08 github

Replying to https://github.com/ValveSoftware/Proton/issues/8072#issuecomment-5579166996

Those are proton logs. You need to add PROTON_LOG=1 to your launch options and a log file will be generated in your home directory named steam-2183900.log

OOstekages 2026-09-08 github

I seem to encounter very similar, almost identical issues to the latest posters, also on kernel 7.2.x - I add comment here - not to bloat or clobber the thread - but in case my logs provide any additional details not collected yet :)

I checked journalctl, but there's no entries at all. Which seems to indicate it's not a kernel level crash, but rather a user/game-space crash.

report_2026_09_05_23_05_33_pid412.tar.gz - Contains crashdump and error.yaml from steam appdata

steam-2183900.log.tar.gz

Distro: EndeavourOS / Arch
Kernel: 7.2.3-arch1-2
GPU: NVIDIA RTX 3070
Driver: 610.57.04
Session: Hyprland / Wayland
Game: Space Marine 2, Patch 14.2
Proton tested:

  • Proton Experimental
  • Proton 11.0-2

Behaviour:

  • Campaign co-op
  • Game runs normally for ~10–40 min
  • Then crashes with EXCEPTION_ACCESS_VIOLATION
  • No NVIDIA Xid / GPU / OOM kernel errors
  • Reproducible across Proton Experimental and Proton 11.0-2

Crash:
EXCEPTION_ACCESS_VIOLATION
RIP = 0x142158FEE

Proton log:
code=c0000005
addr=0000000142158FEE
read from near-null address

Post-crash RPC_S_SERVER_UNAVAILABLE occurs ~18 seconds AFTER the crash,
so does not appear causal.

LLegion495 2026-09-08 github

steam-2183900.zip

Got my crashlog here.
Distro: CachyOS
Kernel: 7.2.3-1 linux-cachyos
GPU: AMD 7900XTX
Session: Wayland
Game: Space Marine 2, Patch 14.2

JJMarcosHP 2026-09-08 github

My log from 7.2.2 after 1hr playing siege normal difficulty and the first sector on hard, using proton-cachyos latest on openSUSE Tumbleweed.

Command line options:
ENABLE_VKBASALT=1 PROTON_FSR4_RDNA3_UPGRADE=1 PROTON_DISCORD_BRIDGE=1 LOW_LATENCY_LAYER=1 PROTON_LOG=1 gamemoderun %command%

Error:
EXCEPTION_ACCESS_VIOLATION

Click to expand
5839.463:01b0:01c4:warn:seh:dispatch_exception backtrace: --- Exception 0xc0000005.
5839.464:01b0:01c4:trace:seh:dispatch_exception code=c0000005 (EXCEPTION_ACCESS_VIOLATION) flags=0 addr=0000000142158FEE
5839.464:01b0:01c4:trace:seh:dispatch_exception  info[0]=0000000000000000
5839.464:01b0:01c4:trace:seh:dispatch_exception  info[1]=000000000000006B
5839.464:01b0:01c4:trace:seh:dispatch_exception rip=0000000142158fee rsp=00000000198bfc48 rbp=0000000142159040 eflags=00010246
5839.464:01b0:01c4:trace:seh:dispatch_exception rax=0000000000000000 rbx=00000001543c91c0 rcx=0000000000000003 rdx=000000000000000c
5839.464:01b0:01c4:trace:seh:dispatch_exception rsi=000000015bd6f440 rdi=000000015bd6f400  r8=00000001543c91a0  r9=0000000000000013
5839.464:01b0:01c4:trace:seh:dispatch_exception r10=00006ffffc180000 r11=0000000032d91c70 r12=0000000000000000 r13=00000000082a4100
5839.464:01b0:01c4:trace:seh:dispatch_exception r14=000000011cd017f8 r15=00000000198bfce0 mxcsr=00001f80 cs=0033 ss=002b
5839.464:01b0:01c4:warn:seh:virtual_unwind backtrace: 0000000142158FEE: L"Warhammer 40000 Space Marine 2 - Retail.exe" + 0000000002158FEE.
5839.464:01b0:01c4:trace:unwind:RtlVirtualUnwind2 type 1 base 140000000 rip 142158fee rva 2158fee rsp 198bfc48
5839.464:01b0:01c4:warn:seh:virtual_unwind backtrace: 0000000142175F8E: L"Warhammer 40000 Space Marine 2 - Retail.exe" + 0000000002175F8E.
5839.464:01b0:01c4:trace:unwind:RtlVirtualUnwind2 type 1 base 140000000 rip 142175f8e rva 2175f8e rsp 198bfc50
5839.464:01b0:01c4:trace:unwind:dump_unwind_info **** func 2175e92-2175fa7
5839.464:01b0:01c4:trace:unwind:dump_unwind_info unwind info at 0000000143E97020 flags 4 prolog 0x11 bytes function 0000000142175E92-0000000142175FA7
5839.464:01b0:01c4:trace:unwind:dump_unwind_info     0x11: movq %rdi,0x88(%rsp)
5839.464:01b0:01c4:trace:unwind:dump_unwind_info     0xd: movq %rsi,0x80(%rsp)
5839.464:01b0:01c4:trace:unwind:dump_unwind_info     0x4: movq %rbp,0x78(%rsp)
5839.464:01b0:01c4:trace:unwind:dump_unwind_info     chained to function 0000000142175E8B-0000000142175E92
5839.464:01b0:01c4:trace:unwind:dump_unwind_info unwind info at 0000000143E9700C flags 4 prolog 0x4 bytes function 0000000142175E8B-0000000142175E92
5839.464:01b0:01c4:trace:unwind:dump_unwind_info     0x4: movq %rbx,0x70(%rsp)
5839.464:01b0:01c4:trace:unwind:dump_unwind_info     chained to function 0000000142175E80-0000000142175E8B
5839.464:01b0:01c4:trace:unwind:dump_unwind_info unwind info at 0000000143E97000 flags 0 prolog 0xb bytes function 0000000142175E80-0000000142175E8B
5839.464:01b0:01c4:trace:unwind:dump_unwind_info     0xb: subq $0x58,%rsp
5839.464:01b0:01c4:trace:unwind:dump_unwind_info     0x7: pushq %r15
5839.464:01b0:01c4:trace:unwind:dump_unwind_info     0x5: pushq %r12
5839.464:01b0:01c4:warn:seh:virtual_unwind backtrace: 00000001421590AA: L"Warhammer 40000 Space Marine 2 - Retail.exe" + 00000000021590AA.
5839.464:01b0:01c4:trace:unwind:RtlVirtualUnwind2 type 1 base 140000000 rip 1421590aa rva 21590aa rsp 198bfcc0
5839.464:01b0:01c4:trace:unwind:dump_unwind_info **** func 2159040-21590fe
5839.464:01b0:01c4:trace:unwind:dump_unwind_info unwind info at 0000000143E96370 flags 0 prolog 0x10 bytes function 0000000142159040-00000001421590FE
5839.464:01b0:01c4:trace:unwind:dump_unwind_info     0x10: movq %rsi,0x68(%rsp)
5839.464:01b0:01c4:trace:unwind:dump_unwind_info     0x10: movq %rbx,0x60(%rsp)
5839.464:01b0:01c4:trace:unwind:dump_unwind_info     0x10: subq $0x50,%rsp
5839.464:01b0:01c4:trace:unwind:dump_unwind_info     0xc: pushq %rdi
5839.464:01b0:01c4:warn:seh:virtual_unwind backtrace: 0000000142658DCD: L"Warhammer 40000 Space Marine 2 - Retail.exe" + 0000000002658DCD.
5839.464:01b0:01c4:trace:unwind:RtlVirtualUnwind2 type 1 base 140000000 rip 142658dcd rva 2658dcd rsp 198bfd20
5839.464:01b0:01c4:trace:unwind:dump_unwind_info **** func 2658d50-2658e93
5839.464:01b0:01c4:trace:unwind:dump_unwind_info unwind info at 0000000143EC395C flags 0 prolog 0x19 bytes function 0000000142658D50-0000000142658E93
5839.464:01b0:01c4:trace:unwind:dump_unwind_info     0x19: movq %rdi,0x78(%rsp)
5839.464:01b0:01c4:trace:unwind:dump_unwind_info     0x19: movq %rsi,0x70(%rsp)
5839.464:01b0:01c4:trace:unwind:dump_unwind_info     0x19: movq %rbp,0x68(%rsp)
5839.464:01b0:01c4:trace:unwind:dump_unwind_info     0x19: movq %rbx,0x60(%rsp)
5839.464:01b0:01c4:trace:unwind:dump_unwind_info     0x19: subq $0x50,%rsp
5839.464:01b0:01c4:trace:unwind:dump_unwind_info     0x15: pushq %r14
5839.464:01b0:01c4:warn:seh:virtual_unwind backtrace: 00000001426AC595: L"Warhammer 40000 Space Marine 2 - Retail.exe" + 00000000026AC595.
5839.464:01b0:01c4:trace:unwind:RtlVirtualUnwind2 type 1 base 140000000 rip 1426ac595 rva 26ac595 rsp 198bfd80
5839.464:01b0:01c4:trace:unwind:dump_unwind_info **** func 26ac41b-26ac66d
5839.464:01b0:01c4:trace:unwind:dump_unwind_info unwind info at 0000000143ECA5E4 flags 4 prolog 0x4 bytes function 00000001426AC41B-00000001426AC66D
5839.464:01b0:01c4:trace:unwind:dump_unwind_info     0x4: movq %r15,0xb0(%rsp)
5839.464:01b0:01c4:trace:unwind:dump_unwind_info     chained to function 00000001426AC400-00000001426AC41B
5839.464:01b0:01c4:trace:unwind:dump_unwind_info unwind info at 0000000143ECA5C0 flags 4 prolog 0x1b bytes function 00000001426AC400-00000001426AC41B
5839.464:01b0:01c4:trace:unwind:dump_unwind_info     0x1b: movq %r14,0xb8(%rsp)
5839.464:01b0:01c4:trace:unwind:dump_unwind_info     0x13: movq %r13,0xc0(%rsp)
5839.464:01b0:01c4:trace:unwind:dump_unwind_info     0xc: movq %r12,0xc8(%rsp)
5839.464:01b0:01c4:trace:unwind:dump_unwind_info     0x8: movq %rdi,0xd0(%rsp)
5839.464:01b0:01c4:trace:unwind:dump_unwind_info     0x4: movq %rsi,0x100(%rsp)
5839.464:01b0:01c4:trace:unwind:dump_unwind_info     chained to function 00000001426AC3F0-00000001426AC400
5839.464:01b0:01c4:trace:unwind:dump_unwind_info unwind info at 0000000143D26E94 flags 0 prolog 0x10 bytes function 00000001426AC3F0-00000001426AC400
5839.464:01b0:01c4:trace:unwind:dump_unwind_info     0x10: subq $0xd8,%rsp
5839.464:01b0:01c4:trace:unwind:dump_unwind_info     0x5: pushq %rbx
5839.464:01b0:01c4:trace:unwind:dump_unwind_info     0x4: pushq %rbp
5839.464:01b0:01c4:warn:seh:virtual_unwind backtrace: 00000001426DB7A9: L"Warhammer 40000 Space Marine 2 - Retail.exe" + 00000000026DB7A9.
5839.464:01b0:01c4:trace:unwind:RtlVirtualUnwind2 type 1 base 140000000 rip 1426db7a9 rva 26db7a9 rsp 198bfe70
5839.464:01b0:01c4:trace:unwind:dump_unwind_info **** func 26db780-26dbb7c
5839.464:01b0:01c4:trace:unwind:dump_unwind_info unwind info at 0000000143ECDDA8 flags 0 prolog 0x1a bytes function 00000001426DB780-00000001426DBB7C
5839.464:01b0:01c4:trace:unwind:dump_unwind_info     0x1a: subq $0x58,%rsp
5839.464:01b0:01c4:trace:unwind:dump_unwind_info     0x16: pushq %r15
5839.464:01b0:01c4:trace:unwind:dump_unwind_info     0x14: pushq %r14
5839.464:01b0:01c4:trace:unwind:dump_unwind_info     0x12: pushq %r13
5839.464:01b0:01c4:trace:unwind:dump_unwind_info     0x10: pushq %r12
5839.464:01b0:01c4:trace:unwind:dump_unwind_info     0xe: pushq %rdi
5839.464:01b0:01c4:trace:unwind:dump_unwind_info     0xd: pushq %rsi
5839.464:01b0:01c4:trace:unwind:dump_unwind_info     0xc: pushq %rbp
5839.464:01b0:01c4:trace:unwind:dump_unwind_info     0xb: pushq %rbx
5839.464:01b0:01c4:warn:seh:virtual_unwind backtrace: 00000001426DA4F4: L"Warhammer 40000 Space Marine 2 - Retail.exe" + 00000000026DA4F4.
5839.464:01b0:01c4:trace:unwind:RtlVirtualUnwind2 type 1 base 140000000 rip 1426da4f4 rva 26da4f4 rsp 198bff10
5839.464:01b0:01c4:trace:unwind:dump_unwind_info **** func 26da3e0-26da51a
5839.464:01b0:01c4:trace:unwind:dump_unwind_info unwind info at 0000000143ECDC34 flags 0 prolog 0xa bytes function 00000001426DA3E0-00000001426DA51A
5839.464:01b0:01c4:trace:unwind:dump_unwind_info     0xa: movq %rbx,0x38(%rsp)
5839.464:01b0:01c4:trace:unwind:dump_unwind_info     0xa: subq $0x20,%rsp
5839.464:01b0:01c4:trace:unwind:dump_unwind_info     0x6: pushq %rdi
5839.464:01b0:01c4:warn:seh:virtual_unwind backtrace: 0000000142726CF9: L"Warhammer 40000 Space Marine 2 - Retail.exe" + 0000000002726CF9.
5839.464:01b0:01c4:trace:unwind:RtlVirtualUnwind2 type 1 base 140000000 rip 142726cf9 rva 2726cf9 rsp 198bff40
5839.464:01b0:01c4:trace:unwind:dump_unwind_info **** func 2726cc0-2726d00
5839.464:01b0:01c4:trace:unwind:dump_unwind_info unwind info at 0000000143ED4050 flags 0 prolog 0x4 bytes function 0000000142726CC0-0000000142726D00
5839.464:01b0:01c4:trace:unwind:dump_unwind_info     0x4: subq $0x38,%rsp
5839.464:01b0:01c4:warn:seh:virtual_unwind backtrace: 00006FFFFFEA1649: L"kernel32.dll" + 0000000000011649.
5839.464:01b0:01c4:trace:unwind:RtlVirtualUnwind2 type 1 base 6fffffe90000 rip 6fffffea1649 rva 11649 rsp 198bff80
5839.464:01b0:01c4:trace:unwind:dump_unwind_info **** func 11640-11650
5839.464:01b0:01c4:trace:unwind:dump_unwind_info unwind info at 00006FFFFFED9FE8 flags 0 prolog 0x4 bytes function 00006FFFFFEA1640-00006FFFFFEA1650
5839.464:01b0:01c4:trace:unwind:dump_unwind_info     0x4: subq $0x28,%rsp
5839.464:01b0:01c4:warn:seh:virtual_unwind backtrace: 00006FFFFFF20E2F: L"ntdll.dll" + 0000000000010E2F.
5839.464:01b0:01c4:trace:unwind:RtlVirtualUnwind2 type 1 base 6ffffff10000 rip 6ffffff20e2f rva 10e2f rsp 198bffb0
5839.464:01b0:01c4:trace:unwind:dump_unwind_info **** func 10e18-10e30
5839.464:01b0:01c4:trace:unwind:dump_unwind_info unwind info at 00006FFFFFFD81FC flags 1 prolog 0x4 bytes function 00006FFFFFF20E18-00006FFFFFF20E30
5839.464:01b0:01c4:trace:unwind:dump_unwind_info     0x4: subq $0x28,%rsp
5839.464:01b0:01c4:trace:unwind:dump_unwind_info     handler 00006FFFFFF69420 data at 00006FFFFFFD8208
5839.464:01b0:01c4:trace:seh:call_seh_handlers calling handler 00006FFFFFF69420 (rec=00000000198BFA30, frame=198bffb0 context=00000000198BF540, dispatch=00000000198BECD0)

steam-2183900.zip

KKortesKnight 2026-09-09 github

I hope this helps someone.

System

OS: NixOS 26.11 (Zokor)
KERNEL: 7.2.2
CPU: AMD Ryzen 7 7800X3D 8-Core
GPU: NVIDIA GeForce RTX 5070
GPU DRIVER: NVIDIA 595.91.07
RAM: 31 GB

Problem description (September 3rd, 2026)

I've tested Proton Experimental, Hotfix, 11, 10, and 9. There are two different behaviors:

  1. The game doesn't launch at all and shows Unexpected Error #1 in the launcher.
  2. The game launches, but crashes during missions in online mode with the Crash Dump Sending Utility window.

I had no issues during the campaign. The problems only started when I switched to Operations/online mode.

Solution (September 7th, 2026)

Somehow, I came across this comment and decided to try it on my machine. I switched the kernel from 7.2.2 to 7.1.13 and switched to Proton 11.0-2.

It helped, and now I can play normally and enjoy the game without any issues.

At least, I haven't seen any crashes or other problems after two days of daily gameplay in both campaign and online modes, including long single-session play.

HHWG90 2026-09-13 github

System

OS: CachyOS x86_64
KERNEL: 7.2.5-1-cachyos
CPU: AMD Ryzen 7 9800X3D 8-Core
GPU: NVIDIA GeForce RTX 5090
RAM: 96 GB

Proton GE, Proton Hotfix, 11, 10 and 9 tested. All have the crash occur.

Problem description (September 13th, 2026)

I am still experiencing the same crash on Linux kernel 7.2.5-1-cachyos. Mid-session will just fail. Does not occur on my LTS 6.18 kernel (as far as I can tell)

Ssimifor 2026-09-19 github

the issue is still happening with the most recent kernel releases, right? I've been trying to bisect to find what change made this issue manifest. The problem is that on my end it can take up to 3 hours for the issue to pop up (though it's usually less).

Here's a kernel build for for arch based systems, hopefully it should work on any x64 system. Note that this is just the kernel and not the headers, so not fit for people that need out of tree modules:

https://we.tl/t-H3Gz3PJL6VtkyL6p this link should be available for 3 days

RRombond 2026-09-19 github

Posting a data point that looks like a different failure from the one this thread is tracking, in case it's useful to whoever is bisecting — happy to move this to a separate issue if maintainers prefer.

The reports here are EXCEPTION_ACCESS_VIOLATION, mid-mission, with no kernel-level fault (several people explicitly note journalctl is clean), and improved by the 6.18 LTS kernel. Mine is the opposite on all three counts: a GPU-level fault, at startup, which still reproduces on 6.18 LTS.

Symptom

Crash on the start screen or within ~1s of the main menu rendering. Gameplay is never reached. 100% reproducible, every launch.

Every crash produces an identical kernel fault:

NVRM: Xid (PCI:0000:01:00): 13, pid=<varies>, name=Warhammer 40000, Graphics Exception:
channel 0x0000000b, Class 0000c997, Offset 00000000, Data 00000000

Xid 13 (Graphics Exception — illegal instruction/method), not Xid 31 (page fault). Class 0000c997 is the Ada compute class. Offset and Data are zero on every occurrence.

vkd3d-proton then reports device loss:

err:vkd3d-proton:vkd3d_wait_for_gpu_timeline_semaphore: Failed to wait for Vulkan timeline semaphore, vr -4.
warn:vkd3d-proton:d3d12_device_mark_as_removed: Device ... is lost (reason 0x887a0005, "VK_ERROR_DEVICE_LOST").
err:vkd3d-proton:dxgi_vk_swap_chain_ensure_unsignaled_swapchain_fence: Failed to wait for fences, vr -4
err:vkd3d-proton:dxgi_vk_swap_chain_present_signal_blit_semaphore: Failed to submit present discard, vr = -4.

System

  • GPU: RTX 4070 Ti SUPER (Ada/AD103), nvidia-open-dkms 610.57.04
  • Arch Linux, Wayland session (game under XWayland)
  • Game build 25098992

Ruled out — each verified as actually applied

Variable Tested Result
Kernel 7.2.5, 7.2.3, 6.18.49 LTS identical
Proton 9.0-4f, Experimental experimental-11.0 (vkd3d-proton 3.1.0) identical
NvAPI/DLSS PROTON_DISABLE_NVAPI=1 identical
ReBAR/HVV upload heaps VKD3D_CONFIG=no_upload_hvv identical
Shader/pipeline cache cleared identical
Game files Steam verify nothing repaired
Steam overlay disabled identical

For the NvAPI test I confirmed Proton removed nvapi64.dll from the prefix and that nvapi64 and LaunchCubinShader appear 0 times in the log — worth stating because the game does otherwise drive a CUDA cubin path (NvAPI_D3D12_CreateCubinComputeShaderExV2 / LaunchCubinShader, with several Invalid pointer returns from DXVK-NVAPI) that looked like a promising culprit. Disabling it entirely changes nothing.

Two diagnostics that narrow it

VKD3D_CONFIG=fault (VK_EXT_device_fault) returns an empty report:

err:vkd3d-proton:d3d12_device_report_fault: DEVICE_LOST received, reporting fault.
err:vkd3d-proton:d3d12_device_report_fault: Desc:

No fault address, no vendor info — so no page fault, and none of vkd3d's use-after-free / out-of-bounds diagnostics fire.

VKD3D_CONFIG=log_memory_budget at the moment of the crash:

Memory heap #0 [DEVICE_LOCAL], size 16376 MiB, budget: 15202 MiB, usage: 2821 MiB

2.8 GB of a 15 GB budget — not memory pressure, despite the game polling NtGdiDdDDIQueryStatistics (a wine stub) every frame right up to the fault.

Taken together: an illegal instruction reaching the Ada compute engine, with no bad address and no memory pressure.

Note for anyone bisecting

The only variable I have not been able to test is the NVIDIA driver branch — 610.43.03 and 610.57.04 are in-branch neighbours, so every driver I've run shares a shader compiler. Given the fault is invariant across three kernels and two vkd3d generations, that's where I'd look next, but I'm not in a position to run a cross-branch test on this machine.

Full Proton log available on request.

Ssimifor 2026-09-19 github

@Rombond yours is a different issue, but all issues for a given game go in the same thread so it should remain here anyway. My testing for the other crash mentioned here has been on my amd desktop, but as I also have a nvidia laptop with a 4060, I tried there but the game was working there.

This was with nvidia 615.71.09, so it would be a good idea if you tried upgrading your drivers first and see if that works for you.

Ssimifor 2026-09-20 github

Around 2 hours with my kernel build and no crash yet. If anyone downloaded that build and gave it a spin I'd like to know if it has crashed for you, and if not, how long you played the game

JJMarcosHP 2026-09-21 github

the issue is still happening with the most recent kernel releases, right? I've been trying to bisect to find what change made this issue manifest. The problem is that on my end it can take up to 3 hours for the issue to pop up (though it's usually less).

Here's a kernel build for for arch based systems, hopefully it should work on any x64 system. Note that this is just the kernel and not the headers, so not fit for people that need out of tree modules:

https://we.tl/t-H3Gz3PJL6VtkyL6p this link should be available for 3 days

I installed 7.1.13 from Koji on a Fedora 44 KDE system, after 3 hours of gameplay I got 0 crashes. So something in the Kernel is helping to mitigate that EXCEPTION_ACCESS_VIOLATION, have you figured out with the bisect what the change is?

Ssimifor 2026-09-22 github

@@JMarcosHP The bisect isn't finished, I don't know how it is for others, but if I'm unlucky it can take over 2 hours to crash, this of course makes the bisect harder as it takes longer to know whether a commit is good or if it just hasn't crashed yet.

I have another build for now, if others run the game with it and report back it can help speed things up.
https://we.tl/t-r9athW2qxk1BTicP

Jjegglest 2026-09-27 github

Root cause of the mid-mission crash at Retail.exe+0x2158FEE (resFILE_LOADER, rcx = 3)

TL;DR: This is a game bug that Wine triggers far more often than Windows does.

  • Game side: the game waits on a condition variable once, without re-checking its predicate. A pending file-read callback holds a pointer into that function's stack frame.
  • Wine side: RtlWaitOnAddress() can leave a stale thread alert behind, and it makes that wait return early. Most of these come from the game's tcmalloc, whose spinlock back-off calls WaitOnAddress() with a timeout that can round down to 0 ms.
  • Result: the function returns while reads are still pending. When a read completes, the callback writes through a pointer into the dead stack frame.

A two-part ntdll fix (below) removes the stale alerts. With it I've played 2 h 40 min without a crash, against 8 crashes in about 7 h 20 min before on the same setup.

Setup:

  • Bazzite 44 (testing-44.20260925), kernel 7.2.7-ogc1.1
  • Ryzen 7 9800X3D, RX 9070 XT (RADV, Mesa 26.2.2)
  • Proton Experimental 11.0-20260924
  • Game build 25098992 (Retail 14.2)

The exe loads at its preferred base 0x140000000, so offsets below are relative to that.

Game side

  • The waiter. +0x205AC90 builds a vector of 24-byte records on its stack, each with status 3 (pending). For each record it registers a completion callback capturing [&records, index]; the lambda's ops table is at +0x37C5790. It then submits the batch (+0x216DA90) and waits on the returned future, with no loop:
    EnterCriticalSection(&f->cs);
    if (f->state != 2 && f->state != 3)
        SleepConditionVariableCS(&f->cv, &f->cs, INFINITE);   /* call at +0x205AF82 */
    LeaveCriticalSection(&f->cs);
    
    The SleepConditionVariableCS docs say this needs a loop, with no exception for INFINITE: "Condition variables are subject to spurious wakeups (those not associated with an explicit wake) … you should recheck a predicate (typically in a while loop) after a sleep operation returns."
  • Normal completion is safe. The completion path runs on resFILE_LOADER (+0x2175E80). It sets the state and calls WakeAllConditionVariable(), then runs the callbacks while still holding the critical section. So a real wake can't let the waiter leave before the callbacks finish; only a spurious wakeup can.
  • The crash. After an early return, the callback (+0x2158FD0) does records.data[index].status = 4 or 5 through the dangling &records. records.data is whatever now occupies that stack slot. That was 3 in my dumps and the ones posted here, so cmp dword [rcx+rdx*8+8] faults at 0xB / 0x3B / 0x6B (index 0 / 2 / 4). When the slot happens to hold a valid pointer, you get silent memory corruption instead.
  • It's widespread. The same unlooped wait appears at many other call sites; it looks like an inlined future-wait helper.

Wine side

  • The race. RtlWakeAddressSingle() / RtlWakeAddressAll() take a waiter off the queue under the queue spinlock, but only alert it after dropping the lock.
  • The leftover alert. If the waiter's wait times out in between, RtlWaitOnAddress() returns STATUS_TIMEOUT and the alert stays pending on the thread. The thread's next NtWaitForAlertByThreadId() then returns immediately. That can be an unrelated SleepConditionVariableCS(INFINITE), like the one above.
  • Zero-timeout waits make it common. Wine queues them too.
    • libtcmalloc_minimal.dll's spinlock back-off (gperftools-style SpinLockDelay) calls WaitOnAddress(lock, &locked, 4, ms) with a random delay converted to whole milliseconds, so short delays become 0 ms. It releases the lock with WakeByAddressSingle().
    • A 0 ms waiter is queued for the whole call and times out almost at once, so the releaser often picks exactly such a waiter. That leaves a stale alert on an allocating thread.
    • +0x205AC90 allocates (growing the record vector) right before its wait.
  • This goes beyond what Windows documents.
    • The WaitOnAddress docs list "A previous wake on the same address was abandoned" as a cause of early returns. In Wine the leftover alert belongs to the thread, so an abandoned wake on tcmalloc's lock ends a wait on an unrelated condition variable.
    • WakeByAddressSingle wakes "the first thread to wait", and "other waiting threads continue to wait". Handing that wake to a thread that is already timing out loses it for the thread that is actually waiting.

Evidence

  • Instrumented ntdll, in-game. The build logs whenever a waiter is dequeued as its wait times out. It logged over 2,000 of these in a 44-minute session. The 22 with backtraces all had timeout 0, all came from libtcmalloc_minimal.dll+0x178E, and all were on the game's allocating threads.

  • Reproducer (mingw source at the end of this comment). 8 workers each take a tcmalloc-style spinlock and then do the game's unlooped future wait.

    15 s run on Proton Experimental 11.0-20260924 Future waits Returned while still pending
    Stock 526,409 56,049
    With the fix below 527,657 0
  • Playing, same machine and settings.

    Build Play time Crashes
    Stock Experimental 20260924 about 7 h 20 min over 14 sessions 8
    With the fix (same kernel 7.2.7, same game build) 2 h 40 min 0

    The patched time includes a 1 h 56 min session; my longest session before that was 69 minutes, and it ended in a crash. The instrumented build logged no stale alerts left in the game.

Fix

Two small changes to RtlWaitOnAddress():

  1. Don't queue zero-timeout waits. Just compare the value and return, following the usual Win32 rule that a zero timeout never enters a wait state.
  2. Take the pending alert. If a waiter finds it was dequeued as its wait timed out, it takes the alert the waker is about to send and reports the wake.

The patch is against ValveSoftware/wine experimental_11.0 (adea6cb) and also applies to upstream master. I also have a conformance test for ntdll/tests/sync.c that checks no thread alert is left pending after short waits race with wakes. It fails on current Proton Experimental and passes with the fix.

dlls/ntdll/sync.c
diff --git a/dlls/ntdll/sync.c b/dlls/ntdll/sync.c
index 18e61e4..13d30c3 100644
--- a/dlls/ntdll/sync.c
+++ b/dlls/ntdll/sync.c
@@ -881,6 +881,7 @@ NTSTATUS WINAPI RtlWaitOnAddress( const void *addr, const void *cmp, SIZE_T size
 {
     struct futex_queue *queue = get_futex_queue( addr );
     struct futex_entry entry;
+    BOOL queued = FALSE;
     NTSTATUS ret;
 
     TRACE("addr %p cmp %p size %#Ix timeout %s\n", addr, cmp, size, debugstr_timeout( timeout ));
@@ -888,6 +889,11 @@ NTSTATUS WINAPI RtlWaitOnAddress( const void *addr, const void *cmp, SIZE_T size
     if (size != 1 && size != 2 && size != 4 && size != 8)
         return STATUS_INVALID_PARAMETER;
 
+    /* Don't queue a zero-timeout wait. RtlWakeAddress*() could pick us and alert us only after we have
+     * returned, which would both steal the wake from a real waiter and end this thread's next wait early. */
+    if (timeout && !timeout->QuadPart)
+        return compare_addr( addr, cmp, size ) ? STATUS_TIMEOUT : STATUS_SUCCESS;
+
     entry.addr = addr;
     entry.tid = GetCurrentThreadId();
 
@@ -913,11 +919,16 @@ NTSTATUS WINAPI RtlWaitOnAddress( const void *addr, const void *cmp, SIZE_T size
     if (entry.addr)
     {
         spin_lock( &queue->lock );
-        if (entry.addr)
+        if ((queued = entry.addr != NULL))
             list_remove( &entry.entry );
         spin_unlock( &queue->lock );
     }
 
+    /* If we were dequeued as our wait timed out, the waker alerts us right after releasing the queue lock.
+     * Take that alert and report the wake; otherwise it would end this thread's next wait early. */
+    if (!queued && ret == STATUS_TIMEOUT)
+        ret = NtWaitForAlertByThreadId( NULL, NULL );
+
     TRACE("returning %#lx\n", ret);
 
     if (ret == STATUS_ALERTED) ret = STATUS_SUCCESS;

Why kernel 7.1 vs 7.2?

I don't know which kernel change matters; nothing in this path depends on it directly. How often a stale alert lands on the thread that is about to do this wait depends on tcmalloc lock contention and on thread timing, so a scheduling change in 7.2 could plausibly raise the rate. The kernel isn't doing anything wrong. The reports here of crashes on 6.18 LTS fit this: older kernels make it rarer, not impossible.

The real fix is on Saber's side: make the wait a while loop.

Reproducer: stale_wake.c (build with x86_64-w64-mingw32-gcc -O2 -D__USE_MINGW_ANSI_STDIO=1 -o stale_wake.exe stale_wake.c -lsynchronization)
/* Reproducer for spurious SleepConditionVariableCS() wakeups caused by stale thread alerts.
 *
 * Each worker alternates between:
 *  1. a short timed wait on a shared "noise" condition variable that a pinger thread keeps waking, so that
 *     timeouts race with RtlWakeAddressAll() dequeuing the waiter; and
 *  2. the Space Marine 2 engine's future pattern: `if (!done) SleepConditionVariableCS(INFINITE)`, without a
 *     predicate loop, completed by a dedicated completer thread.
 * A return from (2) while the future is still pending is a spurious wakeup; in the game that is where the
 * waiting function returns and the loader's callback later writes into its dead stack frame.
 *
 * Noise modes: "timed" = (1) above; "poll" = tcmalloc-style spinlock that polls with WaitOnAddress(..., 0) and
 * releases with WakeByAddressSingle(), taken by allocator threads and by each worker right before its future wait
 * (as in the game); "both" (default).
 *
 * Usage: stale_wake.exe [seconds] [workers] [timed|poll|both]
 */
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

struct future
{
    CRITICAL_SECTION cs;
    CONDITION_VARIABLE cv;
    volatile LONG state; /* 0 pending, 2 done */
};

struct worker
{
    struct future f;
    HANDLE go;           /* auto-reset event: worker -> completer */
    LONG64 futures, spurious;
    DWORD seed;
};

static CRITICAL_SECTION noise_cs;
static CONDITION_VARIABLE noise_cv;
static volatile LONG stop, stop_completers;
static volatile LONG alloc_lock;
static BOOL use_timed = TRUE, use_poll = TRUE;

/* tcmalloc-style spinlock: poll with a zero timeout while contended. */
static void alloc_lock_acquire(void)
{
    LONG locked = 1;
    while (InterlockedCompareExchange( &alloc_lock, 1, 0 ))
        WaitOnAddress( &alloc_lock, &locked, sizeof(locked), 0 );
}

static void alloc_lock_release(void)
{
    InterlockedExchange( &alloc_lock, 0 );
    WakeByAddressSingle( (void *)&alloc_lock );
}

static void fake_alloc(void)
{
    volatile int i;
    alloc_lock_acquire();
    for (i = 0; i < 50; i++) ;
    alloc_lock_release();
}

static DWORD WINAPI allocator( void *arg )
{
    while (!stop) fake_alloc();
    return 0;
}

static DWORD next_rand( DWORD *seed )
{
    *seed = *seed * 1103515245 + 12345;
    return *seed >> 8;
}

static void spin_us( LARGE_INTEGER freq, DWORD us )
{
    LARGE_INTEGER start, now;
    QueryPerformanceCounter( &start );
    do QueryPerformanceCounter( &now );
    while ((now.QuadPart - start.QuadPart) * 1000000 / freq.QuadPart < us);
}

static DWORD WINAPI pinger( void *arg )
{
    LARGE_INTEGER freq;
    DWORD seed = 1;

    QueryPerformanceFrequency( &freq );
    while (!stop)
    {
        WakeAllConditionVariable( &noise_cv );
        spin_us( freq, 200 + next_rand( &seed ) % 1600 );
    }
    return 0;
}

static DWORD WINAPI completer( void *arg )
{
    struct worker *w = arg;
    LARGE_INTEGER freq;
    DWORD seed = w->seed ^ 0x5bd1e995;

    QueryPerformanceFrequency( &freq );
    for (;;)
    {
        WaitForSingleObject( w->go, INFINITE );
        if (stop_completers) break;
        spin_us( freq, 20 + next_rand( &seed ) % 400 );
        EnterCriticalSection( &w->f.cs );
        w->f.state = 2;
        WakeAllConditionVariable( &w->f.cv );
        LeaveCriticalSection( &w->f.cs );
    }
    return 0;
}

static DWORD WINAPI worker_thread( void *arg )
{
    struct worker *w = arg;

    while (!stop)
    {
        /* 1: timed wait racing with the pinger's wakes. */
        if (use_timed)
        {
            EnterCriticalSection( &noise_cs );
            SleepConditionVariableCS( &noise_cv, &noise_cs, 1 );
            LeaveCriticalSection( &noise_cs );
        }
        /* 1b: allocate right before waiting, like the game growing its record vector. */
        if (use_poll)
        {
            int i;
            for (i = 0; i < 4; i++) fake_alloc();
        }

        /* 2: single-shot future wait, as in the game. */
        w->f.state = 0;
        SetEvent( w->go );
        EnterCriticalSection( &w->f.cs );
        if (w->f.state != 2)
        {
            SleepConditionVariableCS( &w->f.cv, &w->f.cs, INFINITE );
            if (w->f.state != 2) w->spurious++;
        }
        /* resynchronise properly before the next round */
        while (w->f.state != 2) SleepConditionVariableCS( &w->f.cv, &w->f.cs, INFINITE );
        LeaveCriticalSection( &w->f.cs );
        w->futures++;
    }
    return 0;
}

int main( int argc, char **argv )
{
    int seconds = argc > 1 ? atoi( argv[1] ) : 30, count = argc > 2 ? atoi( argv[2] ) : 8, i;
    const char *mode = argc > 3 ? argv[3] : "both";
    struct worker *workers = calloc( count, sizeof(*workers) );
    HANDLE *threads = calloc( 2 * count + 1, sizeof(*threads) ), allocators[4] = {0};

    if (!strcmp( mode, "timed" )) use_poll = FALSE;
    else if (!strcmp( mode, "poll" )) use_timed = FALSE;
    LONG64 futures = 0, spurious = 0;

    InitializeCriticalSection( &noise_cs );
    InitializeConditionVariable( &noise_cv );
    for (i = 0; i < count; i++)
    {
        InitializeCriticalSection( &workers[i].f.cs );
        InitializeConditionVariable( &workers[i].f.cv );
        workers[i].go = CreateEventW( NULL, FALSE, FALSE, NULL );
        workers[i].seed = 0x9e3779b9 * (i + 1);
        threads[2 * i] = CreateThread( NULL, 0, completer, &workers[i], 0, NULL );
        threads[2 * i + 1] = CreateThread( NULL, 0, worker_thread, &workers[i], 0, NULL );
    }
    threads[2 * count] = CreateThread( NULL, 0, pinger, NULL, 0, NULL );
    if (use_poll)
        for (i = 0; i < ARRAYSIZE(allocators); i++)
            allocators[i] = CreateThread( NULL, 0, allocator, NULL, 0, NULL );

    Sleep( seconds * 1000 );
    stop = 1;
    for (i = 0; i < count; i++) WaitForSingleObject( threads[2 * i + 1], INFINITE );
    stop_completers = 1;
    for (i = 0; i < count; i++)
    {
        SetEvent( workers[i].go );
        WaitForSingleObject( threads[2 * i], INFINITE );
        futures += workers[i].futures;
        spurious += workers[i].spurious;
    }
    WaitForSingleObject( threads[2 * count], INFINITE );
    for (i = 0; i < ARRAYSIZE(allocators); i++)
        if (allocators[i]) WaitForSingleObject( allocators[i], INFINITE );

    printf( "%s: %d s, %d workers: %lld future waits, %lld returned while still pending (spurious)\n",
            mode, seconds, count, (long long)futures, (long long)spurious );
    fflush( stdout );
    return 0;
}
JJMarcosHP 2026-09-27 github

Have you already submitted the patch for Wine? @jegglest

Jjegglest 2026-09-27 github

@JMarcosHP not yet, I wanted to get this information out as quickly as I could. I’ll submit the patch to Wine later today.

Jjegglest 2026-09-27 github

Update: I've revised the ntdll fix after looking harder at the corner cases. Summary of what changed since my comment above:

  • A separate, pre-existing bug is fixed first. RtlWakeAddress*() clear a waiter's entry address and then unlink the entry, which lives on the waiter's stack, all under the queue lock. A waiter that times out reads that address without the lock, so it can see it cleared while the waker is still unlinking, return, and reuse its stack; the waker then writes through stale next/prev pointers. The waiter now checks under the lock.
  • A waiter dequeued as its wait timed out reports the wake (so a WakeByAddressSingle is never lost) and takes the in-flight alert within a 1 ms grace period instead of waiting for it indefinitely. In the stress test the alert was consumed every time.
  • Alerts that arrive while the thread is still queued are ignored, and the wait keeps its original deadline. Wakers always dequeue before alerting, so such an alert can't be for the current wait. This is the safety net for anything the grace period misses, and for alerts left over from thread id reuse.
  • Nothing waits on another thread's progress, and nothing new runs under the queue lock.
  • The conformance test now checks the property Windows documents: after a raced wake, a short wait on a different address must still time out. On Proton Experimental 11.0-20260924 it fails without the fixes in 11 of 12 cases over three runs, and passes with them.
  • Stress test: 69,195 early returns in 529,155 waits before, 0 after, same throughput.
  • In-game: 1 h 21 min on this version without a crash so far, about 4 h in total across the patched builds, against 8 crashes in about 7 h 20 min before. The game's own tcmalloc race no longer shows up in the logs at all with the zero-timeout fix; the remaining timeout/wake race happened once in those 4 hours.
Updated dlls/ntdll/sync.c diff (all four fixes)
diff --git a/dlls/ntdll/sync.c b/dlls/ntdll/sync.c
index 18e61e4..4ddf670 100644
--- a/dlls/ntdll/sync.c
+++ b/dlls/ntdll/sync.c
@@ -881,6 +881,8 @@ NTSTATUS WINAPI RtlWaitOnAddress( const void *addr, const void *cmp, SIZE_T size
 {
     struct futex_queue *queue = get_futex_queue( addr );
     struct futex_entry entry;
+    LARGE_INTEGER deadline;
+    BOOL queued;
     NTSTATUS ret;
 
     TRACE("addr %p cmp %p size %#Ix timeout %s\n", addr, cmp, size, debugstr_timeout( timeout ));
@@ -888,6 +890,19 @@ NTSTATUS WINAPI RtlWaitOnAddress( const void *addr, const void *cmp, SIZE_T size
     if (size != 1 && size != 2 && size != 4 && size != 8)
         return STATUS_INVALID_PARAMETER;
 
+    /* Don't queue a zero-timeout wait. RtlWakeAddress*() could pick us and alert us only after we have
+     * returned, which would both steal the wake from a real waiter and end this thread's next wait early. */
+    if (timeout && !timeout->QuadPart)
+        return compare_addr( addr, cmp, size ) ? STATUS_TIMEOUT : STATUS_SUCCESS;
+
+    /* Use an absolute deadline, so that waiting again after a stale alert doesn't extend the wait. */
+    if (timeout && timeout->QuadPart < 0)
+    {
+        NtQuerySystemTime( &deadline );
+        deadline.QuadPart -= timeout->QuadPart;
+        timeout = &deadline;
+    }
+
     entry.addr = addr;
     entry.tid = GetCurrentThreadId();
 
@@ -907,15 +922,31 @@ NTSTATUS WINAPI RtlWaitOnAddress( const void *addr, const void *cmp, SIZE_T size
 
     spin_unlock( &queue->lock );
 
-    ret = NtWaitForAlertByThreadId( NULL, timeout );
-
-    /* We may have already been removed by a call to RtlWakeAddressSingle() or RtlWakeAddressAll(). */
-    if (entry.addr)
+    for (;;)
     {
+        ret = NtWaitForAlertByThreadId( NULL, timeout );
+
+        /* RtlWakeAddressSingle() and RtlWakeAddressAll() may have removed us already. They still read the
+         * entry after clearing its address, so check under the lock: a waker that has released it is done
+         * with it. An alert received while we are still queued wasn't sent by a waker, since they dequeue us
+         * first: it was left pending by an earlier wait. Ignore it and keep waiting. */
         spin_lock( &queue->lock );
-        if (entry.addr)
+        if ((queued = entry.addr != NULL) && ret != STATUS_ALERTED)
             list_remove( &entry.entry );
         spin_unlock( &queue->lock );
+
+        if (!queued || ret != STATUS_ALERTED) break;
+    }
+
+    if (!queued && ret != STATUS_ALERTED)
+    {
+        /* A waker removed us as our wait ended, so we have been woken. It alerts us right after releasing the
+         * queue lock; take that alert now, or it would end this thread's next wait early. Don't wait for it
+         * indefinitely though, in case the waker was preempted in between. */
+        LARGE_INTEGER grace = {.QuadPart = -10000}; /* 1 ms */
+
+        NtWaitForAlertByThreadId( NULL, &grace );
+        ret = STATUS_SUCCESS;
     }
 
     TRACE("returning %#lx\n", ret);
Jjegglest 2026-09-27 github

Filed the Wine side upstream as https://bugs.winehq.org/show_bug.cgi?id=60397, with the analysis and the fix approach in prose. It's a bug report rather than a merge request because the prototype above was written with an LLM tool, which Wine's Clean Room Guidelines exclude from patches.

JJMarcosHP 2026-09-27 · hidden on GitHub github

Filed the Wine side upstream as https://bugs.winehq.org/show_bug.cgi?id=60397, with the analysis and the fix approach in prose. It's a bug report rather than a merge request because the prototype above was written with an LLM tool, which Wine's Clean Room Guidelines exclude from patches.

Nice, thank you.
Let's wait a decade until Wine devs fix this. /s

JJMarcosHP 2026-09-28 github

Filed the Wine side upstream as https://bugs.winehq.org/show_bug.cgi?id=60397, with the analysis and the fix approach in prose. It's a bug report rather than a merge request because the prototype above was written with an LLM tool, which Wine's Clean Room Guidelines exclude from patches.

Thank you

EElthz 2026-09-29 github

The game is still crashing consistently

OS: Arch Linux
KERNEL: 7.2.7-arch1-1
CPU: AMD Ryzen 7 7800X3D 8-Core
GPU: AMD Radeon RX 6700 XT (radeonsi, navi22, ACO, DRM 3.64, 7.2.7-arch1-1)
GPU DRIVER: 4.6 Mesa 26.2.3-arch1.1
RAM: 32 GB

When the issues started
About 30 days ago there was an update to both the game and proton which broke EAC, making it impossible to launch the game at all, easy enough, simply downgrading to proton 9 or proton 11 worked, few days after that proton experimental got updated and we could launch the game without issues, however, regardless of the proton version used the game started crashing frequently, another report of the issue not from me is here (https://steamcommunity.com/app/2183900/discussions/0/589562254618265197/).

Description of the issue:
When playing operations or siege mode, no matter if in solo or with other people, the game will crash after 2 to 50 minutes of playing, disabling EAC and playing offline didn't fix this issue, the crash happens this way, you will get a pop-up with a crash report window that asks you to send or decline to send a report, however the window is blank and doesn't show why the game crashed, furthermore the game will keep working for a few more minutes after the crash window pop up until it eventually freezes and closes down.

Since then I've started recording proton logs for the game until crash, here's 3 of them, along with them there's some crash logs automatically generated by the game, however these are not always generated during a crash, unsure why.

report_2026_09_22_23_51_53_pid408.zip

steam-2183900OP1.zip

steam-2183901OP2.zip

steam-2183900Siege.zip

crash_data.zip

Some repeated errors seems to be

err:service:device_notify_proc failed to get event, error 1726
dispatch_exception code=6ba (RPC_S_SERVER_UNAVAILABLE)

and

1376.639:0198:019c:warn:threadname:NtSetInformationThread Thread handle 0x6d0 renamed to L"Decals BSP rebuild thread"
1376.675:0198:0208:trace:seh:GetPerformanceInfo (000000001259FDF0, 104)
1376.685:0198:03a0:trace:seh:GetPerformanceInfo (00000000C7CAFDF0, 104)
warn:  CreateDXGIFactory2: Ignoring flags
1376.700:0198:025c:warn:vkd3d-proton:d3d12_pipeline_state_init_graphics_create_info: DSV format is DXGI_FORMAT_UNKNOWN.
1376.745:0198:025c:warn:vkd3d-proton:vkd3d_view_map_create_view2: Intense view map pressure! Got 1024 views in hash map 00000000fa0e9920. This may lead to out-of-memory errors in the extreme case.
1376.746:0198:025c:warn:vkd3d-proton:vkd3d_view_map_create_view2: Intense view map pressure! Got 2048 views in hash map 00000000fa0e9920. This may lead to out-of-memory errors in the extreme case.
1376.746:0198:025c:warn:vkd3d-proton:vkd3d_view_map_create_view2: Intense view map pressure! Got 3072 views in hash map 00000000fa0e9920. This may lead to out-of-memory errors in the extreme case.
1376.748:0198:025c:warn:vkd3d-proton:vkd3d_view_map_create_view2: Intense view map pressure! Got 4096 views in hash map 00000000fa0e9920. This may lead to out-of-memory errors in the extreme case.

While the game internal crash report indicates
"memory info": " Title memory: 5498.8/11073.2 mb (0.0 free)\nGeomStreaming: 547.1/550.0 mb\n TexStreaming: 1836.4/6179.2 mb (0.0 mips drop)\nReserved memory: 1000.0, 0.0 temp [mb]",

I can't make sense whenever it's a proton, sm2 or EAC issue, thought the game seems to be running fine on windows, I hope this can be helpful in making sense on what is going on.

Small edit:
Just to be clear before September I used to play this game quite a lot at max difficulties even in siege which generated a very large a mount of enemies and never crashed, for over a year the game ran perfectly without issues.

Jjegglest 2026-09-30 github

Windows comparison, and the probe used for it

The Wine maintainer's reply on Wine bug 60397 was that an alert left pending when a wake races a timed-out wait is inherent to Win32 futexes and cannot be avoided. To check that, I ran two programs on Windows 11 and on stock Proton Experimental on the same machine (Windows in a QEMU/KVM VM with 4 logical processors):

Windows 11 25H2 (26200.9457) Proton Experimental 11.0-20260924
Zero-timeout RtlWaitOnAddress() calls that timed out while a waker was dequeuing them, of 20,000 (RtlWakeAddressSingle / RtlWakeAddressAll) 39 / 47 147 / 126
… of those, alerts left pending on the thread 0 / 0 18 / 20
100 ns wait on an unrelated address returning early afterwards 0 (189 samples; a 100 ns wait costs a timer tick on Windows) 22 / 27 of 20,000
Unlooped SleepConditionVariableCS(INFINITE) returning while the future was still pending, stale_wake.exe 15 8 poll (source in my first comment above) 0 of 100,097 69,195 of 529,155 (13%)
same, both / timed modes 0 of 26,073 / 0 of 85,325 24,088 of 137,275 / 45 of 139,069

So on Windows the wake that races a timed-out wait is consumed, not left pending, and the unlooped condition-variable wait never returned early in 100,000 tries. That is the shape of Windows' implementation: the wait block carries a flag that the waker and a timing-out waiter exchange; a waiter that finds itself already claimed does a second, untimed NtWaitForAlertByThreadId() to take the wake, and a waker that finds the waiter already timed out doesn't alert it. Wine's waiter returns STATUS_TIMEOUT and leaves the alert for the thread's next wait.

The game still has to loop its wait (Saber ticket 12458). This only establishes that the early return it hits is Wine behaviour, not Windows behaviour.

Patch status. The ntdll patch is now v5 and follows Windows here: the dequeued waiter takes the in-flight alert with an untimed wait (no 1 ms grace period any more), and the "ignore alerts while still queued" part is gone, since Windows does return on any alert and nothing is left for it to catch. The use-after-return fix stays, in a form that keeps the unlocked fast path. With v5: the probe gives 0 pending alerts and 0 early returns, stale_wake 0 spurious wakeups in all three modes at unchanged throughput, and Wine's ntdll:sync suite with a test added for this passes 441/441 in three runs, where stock fails the new test with 23–245 pending alerts per case. The same test binary passes on Windows 11 (441 tests, 0 failures; kernel32:sync 0 failures too). WINE_STALE_ALERT_FIX=0 still gives the A/B build. The three patches are below.

raced_wake_probe.c — build with x86_64-w64-mingw32-gcc -O2 -D__USE_MINGW_ANSI_STDIO=1 -o raced_wake_probe.exe raced_wake_probe.c
/* Probe for a stale thread alert after a RtlWaitOnAddress() wake races the end of a short wait.
 *
 * A waker thread loops RtlWakeAddressSingle()/RtlWakeAddressAll() on one address while the main thread does short
 * waits on it (timeout 0, then 100 ns), so that wakes race with the waits timing out. After each wait the thread
 * checks whether the wake left an alert pending on it:
 *  - "probe" pass: NtWaitForAlertByThreadId(NULL, 0) returns STATUS_ALERTED if an alert is pending (and takes it);
 *  - "early" pass: a 100 ns RtlWaitOnAddress() on an unrelated address must time out. Anything else is an early
 *    return: in the game, that is what ends the unlooped SleepConditionVariableCS(INFINITE) early.
 * Same measurement as the proposed Wine test test_wait_on_address_raced_wake(), built to run on Windows and Wine.
 *
 * Usage: raced_wake_probe.exe [iterations per pass, default 20000] [seconds cap per pass, default 3]
 */
#include <windows.h>
#include <winternl.h>
#include <stdio.h>
#include <stdlib.h>

#ifndef STATUS_SUCCESS
#define STATUS_SUCCESS ((NTSTATUS)0x00000000)
#endif
#ifndef STATUS_ALERTED
#define STATUS_ALERTED ((NTSTATUS)0x00000101)
#endif
#ifndef STATUS_TIMEOUT
#define STATUS_TIMEOUT ((NTSTATUS)0x00000102)
#endif

static NTSTATUS (NTAPI *pRtlWaitOnAddress)( const void *, const void *, SIZE_T, const LARGE_INTEGER * );
static void (NTAPI *pRtlWakeAddressSingle)( const void * );
static void (NTAPI *pRtlWakeAddressAll)( const void * );
static NTSTATUS (NTAPI *pNtWaitForAlertByThreadId)( const void *, const LARGE_INTEGER * );
static NTSTATUS (NTAPI *pRtlGetVersion)( RTL_OSVERSIONINFOW * );
static const char * (CDECL *pwine_get_version)(void);

static volatile LONG address, stop;
static BOOL wake_all;

struct result
{
    unsigned int waits, success, timeout, other, stale, early;
};

static DWORD WINAPI waker_thread( void *arg )
{
    while (!stop)
    {
        if (wake_all) pRtlWakeAddressAll( (const void *)&address );
        else pRtlWakeAddressSingle( (const void *)&address );
    }
    return 0;
}

/* Race short waits against the waker. With probe, look for a pending alert after each wait; otherwise do the
 * 100 ns wait on another address, which must time out. */
static void run_pass( LONGLONG wait_timeout, BOOL probe, unsigned int iterations, DWORD cap_ms, struct result *r )
{
    static const LARGE_INTEGER zero;
    LARGE_INTEGER timeout;
    LONG compare = 0, other = 0;
    DWORD start = GetTickCount();
    NTSTATUS status;
    unsigned int i;

    memset( r, 0, sizeof(*r) );
    for (i = 0; i < iterations && GetTickCount() - start < cap_ms; i++)
    {
        timeout.QuadPart = wait_timeout;
        status = pRtlWaitOnAddress( (const void *)&address, &compare, sizeof(compare), &timeout );
        r->waits++;
        if (status == STATUS_SUCCESS) r->success++;
        else if (status == STATUS_TIMEOUT) r->timeout++;
        else r->other++;

        if (probe)
        {
            if (pNtWaitForAlertByThreadId( NULL, &zero ) == STATUS_ALERTED) r->stale++;
        }
        else
        {
            timeout.QuadPart = -1;
            if (pRtlWaitOnAddress( &other, &compare, sizeof(compare), &timeout ) != STATUS_TIMEOUT) r->early++;
        }
    }
}

int main( int argc, char **argv )
{
    unsigned int iterations = argc > 1 ? atoi( argv[1] ) : 20000, total_stale = 0, total_early = 0, i;
    DWORD cap_ms = (argc > 2 ? atoi( argv[2] ) : 3) * 1000;
    HMODULE ntdll = GetModuleHandleA( "ntdll.dll" );
    RTL_OSVERSIONINFOW ver = { sizeof(ver) };
    struct result r;
    HANDLE thread;

    setvbuf( stdout, NULL, _IONBF, 0 ); /* show each pass as it completes, also through a pipe */

    pRtlWaitOnAddress = (void *)GetProcAddress( ntdll, "RtlWaitOnAddress" );
    pRtlWakeAddressSingle = (void *)GetProcAddress( ntdll, "RtlWakeAddressSingle" );
    pRtlWakeAddressAll = (void *)GetProcAddress( ntdll, "RtlWakeAddressAll" );
    pNtWaitForAlertByThreadId = (void *)GetProcAddress( ntdll, "NtWaitForAlertByThreadId" );
    pRtlGetVersion = (void *)GetProcAddress( ntdll, "RtlGetVersion" );
    pwine_get_version = (void *)GetProcAddress( ntdll, "wine_get_version" );
    if (!pRtlWaitOnAddress || !pRtlWakeAddressSingle || !pRtlWakeAddressAll || !pNtWaitForAlertByThreadId)
    {
        fprintf( stderr, "ntdll lacks RtlWaitOnAddress or NtWaitForAlertByThreadId (needs Windows 8 or later)\n" );
        return 1;
    }

    if (pRtlGetVersion) pRtlGetVersion( &ver );
    printf( "OS %lu.%lu build %lu%s%s, %lu processors\n", ver.dwMajorVersion, ver.dwMinorVersion, ver.dwBuildNumber,
            pwine_get_version ? ", Wine " : "", pwine_get_version ? pwine_get_version() : "",
            (unsigned long)GetActiveProcessorCount( ALL_PROCESSOR_GROUPS ) );

    /* A pending alert from anything before us would be misread as ours. */
    {
        static const LARGE_INTEGER zero;
        pNtWaitForAlertByThreadId( NULL, &zero );
    }

    for (i = 0; i < 8; i++)
    {
        LONGLONG wait_timeout = (i & 4) ? -1 : 0;
        BOOL probe = !(i & 1);

        wake_all = !!(i & 2);
        printf( "timeout %3d ns, wake %-6s, %s: ", (int)-wait_timeout * 100, wake_all ? "all" : "single",
                probe ? "probe" : "early" );
        stop = 0;
        thread = CreateThread( NULL, 0, waker_thread, NULL, 0, NULL );
        run_pass( wait_timeout, probe, iterations, cap_ms, &r );
        InterlockedExchange( &stop, 1 );
        WaitForSingleObject( thread, INFINITE );
        CloseHandle( thread );

        printf( "%6u waits (%6u woken, %6u timed out, %u other)", r.waits, r.success, r.timeout, r.other );
        if (probe) printf( ", %u stale alerts\n", r.stale );
        else printf( ", %u early returns on another address\n", r.early );
        total_stale += r.stale;
        total_early += r.early;
    }

    printf( "total: %u stale alerts, %u early returns\n", total_stale, total_early );
    return 0;
}
Raw output on Windows: raced_wake_probe.exe 20000 3, then stale_wake.exe 15 8 poll|both|timed

Microsoft Windows [Version 10.0.26200.9457]
=== raced_wake_probe.exe 20000 3 ===
OS 10.0 build 26200, 4 processors
timeout   0 ns, wake single, probe:  20000 waits ( 19961 woken,     39 timed out, 0 other), 0 stale alerts
timeout   0 ns, wake single, early:    189 waits (   160 woken,     29 timed out, 0 other), 0 early returns on another address
timeout   0 ns, wake all   , probe:  20000 waits ( 19953 woken,     47 timed out, 0 other), 0 stale alerts
timeout   0 ns, wake all   , early:    189 waits (   183 woken,      6 timed out, 0 other), 0 early returns on another address
timeout 100 ns, wake single, probe:  20000 waits ( 20000 woken,      0 timed out, 0 other), 0 stale alerts
timeout 100 ns, wake single, early:    190 waits (   190 woken,      0 timed out, 0 other), 0 early returns on another address
timeout 100 ns, wake all   , probe:  20000 waits ( 20000 woken,      0 timed out, 0 other), 0 stale alerts
timeout 100 ns, wake all   , early:    189 waits (   189 woken,      0 timed out, 0 other), 0 early returns on another address
total: 0 stale alerts, 0 early returns
=== stale_wake.exe 15 8 poll ===
poll: 15 s, 8 workers: 100097 future waits, 0 returned while still pending (spurious)
=== stale_wake.exe 15 8 both ===
both: 15 s, 8 workers: 26073 future waits, 0 returned while still pending (spurious)
=== stale_wake.exe 15 8 timed ===
timed: 15 s, 8 workers: 85325 future waits, 0 returned while still pending (spurious)

For the record, the Wine side of the probe (raced_wake_probe.exe 20000 2 under Proton Experimental's wine, 16 processors) totalled 41 pending alerts and 59 early returns over the eight passes; with the patched ntdll (v4) it was 0 and 0.

v5 ntdll patches (against Valve Wine adea6cb = Wine master for this code): ordering fix, in-flight alert consume, test
diff --git a/dlls/ntdll/sync.c b/dlls/ntdll/sync.c
index 18e61e4..acf2df5 100644
--- a/dlls/ntdll/sync.c
+++ b/dlls/ntdll/sync.c
@@ -881,6 +881,7 @@ NTSTATUS WINAPI RtlWaitOnAddress( const void *addr, const void *cmp, SIZE_T size
 {
     struct futex_queue *queue = get_futex_queue( addr );
     struct futex_entry entry;
+    BOOL queued = FALSE;
     NTSTATUS ret;
 
     TRACE("addr %p cmp %p size %#Ix timeout %s\n", addr, cmp, size, debugstr_timeout( timeout ));
@@ -909,15 +910,25 @@ NTSTATUS WINAPI RtlWaitOnAddress( const void *addr, const void *cmp, SIZE_T size
 
     ret = NtWaitForAlertByThreadId( NULL, timeout );
 
-    /* We may have already been removed by a call to RtlWakeAddressSingle() or RtlWakeAddressAll(). */
-    if (entry.addr)
+    /* We may have already been removed by a call to RtlWakeAddressSingle() or RtlWakeAddressAll(). They clear
+     * the address last, with release semantics: once it is NULL the waker is done with the entry. */
+    if (ReadPointerAcquire( (void * const volatile *)&entry.addr ))
     {
         spin_lock( &queue->lock );
-        if (entry.addr)
+        if ((queued = entry.addr != NULL))
             list_remove( &entry.entry );
         spin_unlock( &queue->lock );
     }
 
+    if (!queued && ret == STATUS_TIMEOUT)
+    {
+        /* A waker removed us as the wait timed out: we have been woken, and the waker alerts us right after
+         * releasing the queue lock. Take that alert, as Windows does, or it would end this thread's next wait
+         * early, whatever it waits for. */
+        NtWaitForAlertByThreadId( NULL, NULL );
+        ret = STATUS_SUCCESS;
+    }
+
     TRACE("returning %#lx\n", ret);
 
     if (ret == STATUS_ALERTED) ret = STATUS_SUCCESS;
@@ -947,14 +958,17 @@ void WINAPI RtlWakeAddressAll( const void *addr )
     {
         if (entry->addr == addr)
         {
-            entry->addr = NULL;
-            list_remove( &entry->entry );
             if (count == ARRAY_SIZE(tids))
             {
                 NtAlertMultipleThreadByThreadId( tids, count, NULL, NULL );
                 count = 0;
             }
             tids[count++] = (HANDLE)(ULONG_PTR)entry->tid;
+            list_remove( &entry->entry );
+
+            /* The entry is on the waiter's stack, and the waiter may return as soon as it sees the address
+             * cleared, so this must be our last access to it. */
+            WritePointerRelease( (void * volatile *)&entry->addr, NULL );
         }
     }
 
@@ -994,8 +1008,11 @@ void WINAPI RtlWakeAddressSingle( const void *addr )
             /* Remove this entry from the queue, so that a simultaneous call to
              * RtlWakeAddressSingle() will not also wake it—two simultaneous
              * calls must wake at least two waiters if they exist. */
-            entry->addr = NULL;
             list_remove( &entry->entry );
+
+            /* The entry is on the waiter's stack, and the waiter may return as soon as it sees the address
+             * cleared, so this must be our last access to it. */
+            WritePointerRelease( (void * volatile *)&entry->addr, NULL );
             break;
         }
     }
diff --git a/dlls/ntdll/tests/sync.c b/dlls/ntdll/tests/sync.c
index dcbb8b1..0239280 100644
--- a/dlls/ntdll/tests/sync.c
+++ b/dlls/ntdll/tests/sync.c
@@ -615,6 +615,85 @@ static void test_wait_on_address(void)
     ok(address == 0, "got %s\n", wine_dbgstr_longlong(address));
 }
 
+struct wait_on_address_waker
+{
+    LONG address;
+    volatile LONG stop;
+    BOOL wake_all;
+};
+
+static DWORD WINAPI wait_on_address_waker_thread( void *arg )
+{
+    struct wait_on_address_waker *waker = arg;
+
+    while (!waker->stop)
+    {
+        if (waker->wake_all) pRtlWakeAddressAll( &waker->address );
+        else pRtlWakeAddressSingle( &waker->address );
+    }
+    return 0;
+}
+
+static void test_wait_on_address_raced_wake(void)
+{
+    static const LONGLONG timeouts[] = {0, -1};
+    static const LARGE_INTEGER zero;
+    struct wait_on_address_waker waker;
+    unsigned int i, count, pending, early, failed;
+    LARGE_INTEGER timeout;
+    LONG compare = 0, other = 0;
+    NTSTATUS status;
+    HANDLE thread;
+    DWORD start;
+
+    if (!pRtlWaitOnAddress)
+    {
+        win_skip("RtlWaitOnAddress not supported, skipping test\n");
+        return;
+    }
+
+    /* A wake that races the end of a short wait may be taken by that wait, but it must not leave an alert
+     * pending on the thread, which would end its next wait on anything early. */
+    for (i = 0; i < ARRAY_SIZE(timeouts) * 2; i++)
+    {
+        winetest_push_context( "timeout %s, %s", wine_dbgstr_longlong( timeouts[i / 2] ),
+                               i % 2 ? "wake all" : "wake single" );
+
+        waker.address = 0;
+        waker.stop = 0;
+        waker.wake_all = i % 2;
+        thread = CreateThread( NULL, 0, wait_on_address_waker_thread, &waker, 0, NULL );
+
+        pending = early = failed = 0;
+        start = GetTickCount();
+        for (count = 0; count < 20000 && GetTickCount() - start < 1000; count++)
+        {
+            timeout.QuadPart = timeouts[i / 2];
+            status = pRtlWaitOnAddress( &waker.address, &compare, sizeof(compare), &timeout );
+            if (status != STATUS_SUCCESS && status != STATUS_TIMEOUT) failed++;
+
+            if (pNtWaitForAlertByThreadId)
+            {
+                if (pNtWaitForAlertByThreadId( NULL, &zero ) == STATUS_ALERTED) pending++;
+            }
+            else
+            {
+                timeout.QuadPart = -1;
+                if (pRtlWaitOnAddress( &other, &compare, sizeof(compare), &timeout ) != STATUS_TIMEOUT) early++;
+            }
+        }
+
+        waker.stop = 1;
+        WaitForSingleObject( thread, INFINITE );
+        CloseHandle( thread );
+
+        ok( !failed, "%u of %u waits failed\n", failed, count );
+        ok( !pending, "%u of %u waits left an alert pending\n", pending, count );
+        ok( !early, "%u of %u waits on another address returned early\n", early, count );
+        winetest_pop_context();
+    }
+}
+
 static HANDLE thread_ready, thread_done;
 
 static DWORD WINAPI resource_shared_thread(void *arg)
@@ -1474,6 +1553,7 @@ START_TEST(sync)
     pRtlBarrier                     = (void *)GetProcAddress(module, "RtlBarrier");
 
     test_wait_on_address();
+    test_wait_on_address_raced_wake();
     test_event();
     test_mutant();
     test_semaphore();
EErfboom 2026-09-30 github

I know this is for Space Marine 2, but I did want to confirm that on Control Resonant and Alan Wake 2, I was experiencing the same bug on NVIDIA-SMI 615.71.09 KMD Version: 615.71.09 CUDA UMD Version: 13.4 using an RTX 3080. I'm on the latest Bazzite 44, but my journalctl logs looked the same (xid 109) and also had err:winevulkan:signaller_worker error waiting for semaphores, vr -4.

Installing pyroveil and configuring it like this:

{
	"version": 2,
	"type": "pyroveil",
	"matches": [
		{ "spirvExecutionModel": 5365, "action": { "glsl-roundtrip": true } }
	],
	"disabledExtensions": [ "VK_NV_raw_access_chains" ]
}

did indeed stop my freezes (audio still played) on both games. Just wanted to add to the pile here. I can pull whatever logs if asked.

JJMarcosHP 2026-09-30 github

@jegglest The wine devs don't care even with a deep analysis, saying that it was misdiagnosed.

I don't agree on their posture, I think AI can be powerful and a great tool on the right hands.

I recommend you to share your analysis directly on the Proton repo, don't waste your time.

Jjegglest 2026-09-30 github

@JMarcosHP we haven't heard a whole lot from the wine developers yet. I think I'm handling the community well, the patch is public, works for me, and I've supplied a test that demonstrates the behavioral differences between windows and wine. If the implementation I've chosen is not the right way to do it, the wine developers are free to do something else, or, frankly to ignore it. That's their choice.
@Erfboom if you try this patch and it fixes your issues, that's great. Otherwise, I think those reports don't belong in this issue.

EErfboom 2026-09-30 github

Understood! I'll give the patch a try. Thanks!

Hheymaikol 2026-10-01 github

I can independently confirm the Retail.exe+0x2158FEE / RCX = 0x3 crash described above.

I preserved and parsed four Space Marine 2 minidumps from Retail 14.2 on Fedora/NVIDIA. All four have the same signature:

2026-09-17  0xC0000005 READ  Retail.exe+0x2158FEE  RCX=0x3  RDX=0x0  target=0xB
2026-09-21  0xC0000005 READ  Retail.exe+0x2158FEE  RCX=0x3  RDX=0x0  target=0xB
2026-09-21  0xC0000005 READ  Retail.exe+0x2158FEE  RCX=0x3  RDX=0x3  target=0x23
2026-09-30  0xC0000005 READ  Retail.exe+0x2158FEE  RCX=0x3  RDX=0x6  target=0x3B

The scenes were different:

  • pve_daemonhost
  • pve_tyrant
  • pve_acid_bomb
  • pve_dread

Build in all four reports:

Retail_14.2.PATCH.1339092/1344629.PATCH14

I also disassembled the faulting instruction:

142158fee: cmpl $0x1,0x8(%rcx,%rdx,8)

The effective addresses calculated from the exception contexts exactly match the addresses reported by the minidumps.

For example, the latest crash had:

RCX = 0x3
RDX = 0x6

0x3 + (0x6 * 8) + 8 = 0x3B

So this appears to be the same crash described in the root-cause analysis above.

System for the latest occurrence:

  • Fedora 44
  • Kernel 7.2.7
  • NVIDIA GeForce RTX 3060
  • NVIDIA driver 615.71.09
  • Proton 10.0 (Was 11.0.2, and Experimental. All failed with a similar crash)

There was no NVIDIA Xid, GPU reset, system OOM, or Linux-side coredump around the latest occurrence.

I have the original CrashDump.dmp, error.yaml, and screenshots for all four preserved occurrences if they would be useful for further testing.

JJMarcosHP 2026-10-01 github

Is this issue still present on patch 15?

MML0B 2026-10-01 github

Is this issue still present on patch 15?

Yes! Just tested it and crashed with the empy pop-up window

Jjegglest 2026-10-02 github

v6: a second ntsync bug (mutex abandonment) fixed on the server side, and 9.4 hours without a crash

In-game. Since my first patched build on 2026-09-26 I have played 13 sessions, 565 minutes in total (about 9.4 hours), on the patched builds v1 to v6 with no crash, against 8 crashes in about 7 h 20 min before, roughly one per 55 minutes. At that rate 9.4 crash-free hours by luck would be about a one-in-thirty-thousand event. Today's two sessions on v6 (15 and 80 minutes) were the first with the full set below; in the 80-minute session the raced wake that the ntdll fix handles happened at least 5,000 times, every one a zero-timeout WaitOnAddress() from the game's tcmalloc spinlock, and no stale alert got through.

The new bug. Running Wine's kernel32:sync conformance suite on the patched build, two failures in test_mutex() that I had taken for pre-existing noise turned out to be a real ntsync bug, in Proton's server and in upstream Wine alike. With /dev/ntsync, a thread that dies while owning a mutex whose last handle its process has already closed never abandons it, and a thread still waiting on that mutex blocks forever. The end of test_mutex() is exactly that sequence (close the handle, TerminateThread() the owner, expect WAIT_ABANDONED from the waiter) and fails at sync.c:393 and :397 in Proton's tree. It is unrelated to the crash; it is just the next thing the test suite pointed at.

Cause: a thread waiting on an in-process object holds only a duplicate of the ntsync fd, no server reference. When the process closes its last handle the server destroys its object and the mutex drops off the list that abandon_inproc_mutexes() sends NTSYNC_IOC_MUTEX_KILL to on thread death. The kernel object lives on through the waiter's fd, still owned by a dead thread id, and nothing ever kills it. With the handle kept open, or with PROTON_NO_NTSYNC=1, it works; on Windows 11 (same VM as my previous comment) the waiter gets WAIT_ABANDONED 0.1 to 0.7 ms after the terminate, 5 of 5 runs. A 32-bit build of the probe behaves the same on stock Proton, so it is the server, not either architecture's ntdll.

Fix (two server commits, diff below):

  1. When a mutex's in-process sync is destroyed while the kernel object is still owned (NTSYNC_IOC_MUTEX_READ), keep the fd on an orphan list; kill orphans along with the live mutexes on thread death and close them once unowned. Unowned mutexes are closed as before.
  2. That leaves one gap: a mutex that is unowned when its handle is closed can still be acquired later by a wait that was already pending, say a wait-all whose other objects get signaled afterwards, and if that thread then dies the mutex is forgotten again. So when NtClose() (or a close-source DuplicateHandle) finds another thread still using the cached mutex, it passes the cache entry's serial to the server with the close_handle request, the server keeps a reference under that serial, and the entry's last user releases it with a new release_inproc_sync request; a process's records go away with the process. The common close path has no extra server call. Windows abandons the mutex in this case too (3 of 3 runs of the wait-all probe).

Results: kernel32:sync 0 failures in 4 runs (stock: the 2 test_mutex failures), ntdll:sync 441/441, the timed probe below passes its three cases 30 of 30 in both 64- and 32-bit builds (stock: the closed-handle and wait-all cases never return), and the server's fd count is the same after the runs as before.

Build notes, relevant for Proton specifically. Part 2 adds two request fields and one request, so it bumps the server protocol version, and every unix-side ntdll.so must match. Proton runs this game's 32-bit launcher stub (Warhammer 40000 Space Marine 2.exe, which starts the 64-bit EAC bootstrap and the game) the classic way on i386-unix/ntdll.so, so a build that only replaced the 64-bit side stopped the game from starting until I rebuilt the 32-bit unix ntdll as well. My build replaces ntdll.dll and ntdll.so for both architectures plus wineserver, and leaves the other unix libraries stock; for that to work the new request is appended after all existing ones, so that the request numbers win32u.so and friends use are unchanged. A full Proton build has neither concern. The ntdll patches are the three from my previous comment, unchanged.

I'll file the mutex bug with Wine as well and link it here.

Server and unix ntdll diff (commits 5–6 against Proton Experimental 20260924's Wine, adea6cb, on top of the ntdll patches above; run tools/make_requests after applying)
diff --git a/dlls/ntdll/unix/server.c b/dlls/ntdll/unix/server.c
index 112157b..faba490 100644
--- a/dlls/ntdll/unix/server.c
+++ b/dlls/ntdll/unix/server.c
@@ -1863,6 +1863,8 @@ NTSTATUS WINAPI NtAllocateReserveObject( HANDLE *handle, const OBJECT_ATTRIBUTES
 NTSTATUS WINAPI NtDuplicateObject( HANDLE source_process, HANDLE source, HANDLE dest_process, HANDLE *dest,
                                    ACCESS_MASK access, ULONG attributes, ULONG options )
 {
+    struct inproc_sync *cache = NULL;
+    unsigned int serial = 0;
     sigset_t sigset;
     unsigned int ret;
     int fd = -1;
@@ -1899,7 +1901,7 @@ NTSTATUS WINAPI NtDuplicateObject( HANDLE source_process, HANDLE source, HANDLE
     if (options & DUPLICATE_CLOSE_SOURCE)
     {
         fd = remove_fd_from_cache( source );
-        close_inproc_sync( source );
+        cache = close_inproc_sync_begin( source, &serial );
     }
 
     SERVER_START_REQ( dup_handle )
@@ -1910,12 +1912,14 @@ NTSTATUS WINAPI NtDuplicateObject( HANDLE source_process, HANDLE source, HANDLE
         req->access      = access;
         req->attributes  = attributes;
         req->options     = options;
+        req->inproc_serial = serial;
         if (!(ret = wine_server_call( req )))
         {
             if (dest) *dest = wine_server_ptr_handle( reply->handle );
         }
     }
     SERVER_END_REQ;
+    if (cache) close_inproc_sync_end( cache, serial );
 
     server_leave_uninterrupted_section( &fd_cache_mutex, &sigset );
 
@@ -1958,6 +1962,8 @@ NTSTATUS WINAPI NtCompareTokens( HANDLE first, HANDLE second, BOOLEAN *equal )
  */
 NTSTATUS WINAPI NtClose( HANDLE handle )
 {
+    struct inproc_sync *cache;
+    unsigned int serial;
     sigset_t sigset;
     HANDLE port;
     unsigned int ret;
@@ -1973,14 +1979,16 @@ NTSTATUS WINAPI NtClose( HANDLE handle )
     /* always remove the cached fd; if the server request fails we'll just
      * retrieve it again */
     fd = remove_fd_from_cache( handle );
-    close_inproc_sync( handle );
+    cache = close_inproc_sync_begin( handle, &serial );
 
     SERVER_START_REQ( close_handle )
     {
         req->handle = wine_server_obj_handle( handle );
+        req->inproc_serial = serial;
         ret = wine_server_call( req );
     }
     SERVER_END_REQ;
+    if (cache) close_inproc_sync_end( cache, serial );
 
     server_leave_uninterrupted_section( &fd_cache_mutex, &sigset );
 
diff --git a/dlls/ntdll/unix/sync.c b/dlls/ntdll/unix/sync.c
index 67ab945..b0e4a10 100644
--- a/dlls/ntdll/unix/sync.c
+++ b/dlls/ntdll/unix/sync.c
@@ -542,8 +542,11 @@ struct inproc_sync
     unsigned int   access;    /* handle access rights */
     unsigned short type;      /* enum inproc_sync_type as short to save space */
     unsigned short closed;    /* fd has been closed but sync is still referenced */
+    unsigned int   serial;    /* id of this cache entry for the server, 0 if not cached */
 };
 
+static LONG next_inproc_sync_serial;
+
 #define INPROC_SYNC_CACHE_BLOCK_SIZE  (65536 / sizeof(struct inproc_sync))
 #define INPROC_SYNC_CACHE_ENTRIES     128
 
@@ -604,6 +607,7 @@ static struct inproc_sync *cache_inproc_sync( HANDLE handle, struct inproc_sync
     cache->access = sync->access;
     cache->type = sync->type;
     cache->closed = sync->closed;
+    while (!(cache->serial = InterlockedIncrement( &next_inproc_sync_serial ))) ;
     /* Make sure we set the other members before the refcount; this store needs
      * release semantics [paired with the load in get_cached_inproc_sync()].
      * Set the refcount to 2 (one for the handle, one for the caller). */
@@ -628,15 +632,31 @@ static inline LONG interlocked_inc_if_nonzero( LONG *dest )
     return val;
 }
 
+static void release_detached_inproc_sync( unsigned int serial )
+{
+    SERVER_START_REQ( release_inproc_sync )
+    {
+        req->serial = serial;
+        wine_server_call( req );
+    }
+    SERVER_END_REQ;
+}
+
 static void release_inproc_sync( struct inproc_sync *sync )
 {
-    /* save the fd now; as soon as the refcount hits 0 we cannot
+    /* save the fd and serial now; as soon as the refcount hits 0 we cannot
      * access the cache anymore */
     int fd = sync->fd;
+    unsigned int serial = sync->serial;
     LONG ref = InterlockedDecrement( &sync->refcount );
 
     assert( ref >= 0 );
-    if (!ref) close( fd );
+    if (ref) return;
+    close( fd );
+    /* The handle was closed while the object was in use (NtClose() drops the
+     * handle's reference last), and close_inproc_sync_begin() had the server
+     * keep the object under this serial: let it go now. */
+    if (serial) release_detached_inproc_sync( serial );
 }
 
 static struct inproc_sync *get_cached_inproc_sync( HANDLE handle )
@@ -682,6 +702,7 @@ static NTSTATUS get_server_inproc_sync( HANDLE handle, struct inproc_sync *sync
             sync->access = reply->access;
             sync->type = reply->type;
             sync->closed = 0;
+            sync->serial = 0;
         }
     }
     SERVER_END_REQ;
@@ -761,23 +782,47 @@ extern NTSTATUS check_signal_access( struct inproc_sync *sync )
 }
 
 /* caller must hold fd_cache_mutex */
-void close_inproc_sync( HANDLE handle )
+/* First half of closing a handle, before the server request: drop the cache
+ * entry and find out whether another thread is still using the object.
+ * Returns the entry, with a reference held, for close_inproc_sync_end(). */
+struct inproc_sync *close_inproc_sync_begin( HANDLE handle, unsigned int *serial )
 {
     struct inproc_sync *cache;
 
+    *serial = 0;
     if (do_fsync())
     {
         fsync_close( handle );
-        return;
-    }
-    if (inproc_device_fd < 0) return;
-    if ((cache = get_cached_inproc_sync( handle )))
-    {
-        cache->closed = 1;
-        /* once for the reference we just grabbed, and once for the handle */
-        release_inproc_sync( cache );
-        release_inproc_sync( cache );
+        return NULL;
     }
+    if (inproc_device_fd < 0) return NULL;
+    if (!(cache = get_cached_inproc_sync( handle ))) return NULL;
+    cache->closed = 1;
+    /* One reference is the handle's and one is ours; any more belong to
+     * threads in the middle of an operation, typically a wait. Such a thread
+     * can still acquire a mutex through the fd, and the server must then know
+     * the mutex to abandon it if the thread dies, so have the server keep the
+     * object under this entry's serial until the last user releases it. */
+    if (cache->type == INPROC_SYNC_MUTEX && InterlockedCompareExchange( &cache->refcount, 0, 0 ) > 2)
+        *serial = cache->serial;
+    return cache;
+}
+
+/* Second half, after the server request; serial is what the request carried, or 0 */
+void close_inproc_sync_end( struct inproc_sync *cache, unsigned int serial )
+{
+    cache->serial = serial;
+    /* once for the reference we grabbed, and once for the handle */
+    release_inproc_sync( cache );
+    release_inproc_sync( cache );
+}
+
+void close_inproc_sync( HANDLE handle )
+{
+    struct inproc_sync *cache;
+    unsigned int serial;
+
+    if ((cache = close_inproc_sync_begin( handle, &serial ))) close_inproc_sync_end( cache, 0 );
 }
 
 static NTSTATUS inproc_release_semaphore( HANDLE handle, ULONG count, ULONG *prev_count )
diff --git a/dlls/ntdll/unix/unix_private.h b/dlls/ntdll/unix/unix_private.h
index 41163e0..a9608cb 100644
--- a/dlls/ntdll/unix/unix_private.h
+++ b/dlls/ntdll/unix/unix_private.h
@@ -418,6 +418,9 @@ extern NTSTATUS wow64_wine_spawnvp( void *args );
 
 extern void dbg_init(void);
 
+struct inproc_sync;
+extern struct inproc_sync *close_inproc_sync_begin( HANDLE handle, unsigned int *serial );
+extern void close_inproc_sync_end( struct inproc_sync *cache, unsigned int serial );
 extern void close_inproc_sync( HANDLE handle );
 
 extern NTSTATUS call_user_apc_dispatcher( CONTEXT *context_ptr, unsigned int flags, ULONG_PTR arg1, ULONG_PTR arg2,
diff --git a/server/handle.c b/server/handle.c
index a88f94a..b417276 100644
--- a/server/handle.c
+++ b/server/handle.c
@@ -670,7 +670,15 @@ unsigned int get_handle_table_count( struct process *process )
 /* close a handle */
 DECL_HANDLER(close_handle)
 {
-    unsigned int err = close_handle( current->process, req->handle );
+    struct object *obj;
+    unsigned int err;
+
+    if (req->inproc_serial && (obj = get_handle_obj( current->process, req->handle, 0, NULL )))
+    {
+        detach_inproc_sync( current->process, obj, req->inproc_serial );
+        release_object( obj );
+    }
+    err = close_handle( current->process, req->handle );
     set_error( err );
 }
 
@@ -701,7 +709,17 @@ DECL_HANDLER(dup_handle)
         }
         /* close the handle no matter what happened */
         if ((req->options & DUPLICATE_CLOSE_SOURCE) && (src != dst || req->src_handle != reply->handle))
+        {
+            struct object *obj;
+
+            if (req->inproc_serial && src == current->process
+                && (obj = get_handle_obj( src, req->src_handle, 0, NULL )))
+            {
+                detach_inproc_sync( src, obj, req->inproc_serial );
+                release_object( obj );
+            }
             close_handle( src, req->src_handle );
+        }
         release_object( src );
     }
 }
diff --git a/server/inproc_sync.c b/server/inproc_sync.c
index a7020ef..c70de28 100644
--- a/server/inproc_sync.c
+++ b/server/inproc_sync.c
@@ -23,6 +23,7 @@
 #include <assert.h>
 #include <stdint.h>
 #include <stdio.h>
+#include <stdlib.h>
 
 #include "ntstatus.h"
 #define WIN32_NO_STATUS
@@ -75,6 +76,51 @@ struct inproc_sync
 
 static struct list inproc_mutexes = LIST_INIT( inproc_mutexes );
 
+/* Mutexes whose server object was destroyed while a thread still owned them. A client can still hold
+ * a duplicate of the fd (a thread waiting on a handle that has since been closed), and the ntsync
+ * driver abandons a mutex only through NTSYNC_IOC_MUTEX_KILL on that mutex, so the fd is kept until
+ * the owner has released or abandoned it. */
+struct orphan_mutex
+{
+    struct list entry;
+    int         fd;
+};
+
+static struct list orphan_mutexes = LIST_INIT( orphan_mutexes );
+
+static int inproc_mutex_owned( int fd )
+{
+    struct ntsync_mutex_args args = {0};
+    return !ioctl( fd, NTSYNC_IOC_MUTEX_READ, &args ) && args.owner;
+}
+
+static void prune_orphan_mutexes(void)
+{
+    struct orphan_mutex *orphan, *next;
+
+    LIST_FOR_EACH_ENTRY_SAFE( orphan, next, &orphan_mutexes, struct orphan_mutex, entry )
+    {
+        if (inproc_mutex_owned( orphan->fd )) continue;
+        list_remove( &orphan->entry );
+        close( orphan->fd );
+        free( orphan );
+    }
+}
+
+/* In-process syncs whose handle a process closed while one of its threads was still using the cached fd
+ * (typically a wait in progress). That thread can still acquire the mutex through the fd, so the server keeps
+ * the object, and with it the mutex's place on inproc_mutexes, until the client reports that the last user is
+ * done, or the process dies. */
+struct detached_sync
+{
+    struct list         entry;
+    struct process     *process;  /* process that closed the handle; the record dies with it */
+    unsigned int        serial;   /* id chosen by the client, unique within the process */
+    struct inproc_sync *sync;     /* the reference this record holds */
+};
+
+static struct list detached_syncs = LIST_INIT( detached_syncs );
+
 static void inproc_sync_dump( struct object *obj, int verbose );
 static int inproc_sync_signal( struct object *obj, unsigned int access, int signal );
 static void inproc_sync_destroy( struct object *obj );
@@ -262,12 +308,25 @@ static void inproc_sync_destroy( struct object *obj )
     assert( obj->ops == &inproc_sync_ops );
     list_remove( &sync->entry );
     if (do_fsync()) fsync_free_shm_idx( sync->fd );
-    else            close( sync->fd );
+    else if (sync->type == INPROC_SYNC_MUTEX && inproc_mutex_owned( sync->fd ))
+    {
+        struct orphan_mutex *orphan;
+
+        prune_orphan_mutexes();
+        if ((orphan = malloc( sizeof(*orphan) )))
+        {
+            orphan->fd = sync->fd;
+            list_add_tail( &orphan_mutexes, &orphan->entry );
+        }
+        else close( sync->fd );
+    }
+    else close( sync->fd );
 }
 
 void abandon_inproc_mutexes( thread_id_t tid )
 {
     struct inproc_sync *mutex;
+    struct orphan_mutex *orphan;
 
     if (do_fsync())
     {
@@ -278,6 +337,55 @@ void abandon_inproc_mutexes( thread_id_t tid )
 
     LIST_FOR_EACH_ENTRY( mutex, &inproc_mutexes, struct inproc_sync, entry )
         ioctl( mutex->fd, NTSYNC_IOC_MUTEX_KILL, &tid );
+    LIST_FOR_EACH_ENTRY( orphan, &orphan_mutexes, struct orphan_mutex, entry )
+        ioctl( orphan->fd, NTSYNC_IOC_MUTEX_KILL, &tid );
+    prune_orphan_mutexes();
+}
+
+void detach_inproc_sync( struct process *process, struct object *obj, unsigned int serial )
+{
+    struct object *sync;
+    struct detached_sync *detached;
+
+    if (!(sync = get_obj_sync( obj ))) return;
+    if (sync->ops == &inproc_sync_ops && ((struct inproc_sync *)sync)->type == INPROC_SYNC_MUTEX
+        && (detached = malloc( sizeof(*detached) )))
+    {
+        detached->process = process;
+        detached->serial  = serial;
+        detached->sync    = (struct inproc_sync *)sync;  /* keeps the reference from get_obj_sync() */
+        list_add_tail( &detached_syncs, &detached->entry );
+        return;
+    }
+    release_object( sync );
+}
+
+unsigned int release_detached_inproc_sync( struct process *process, unsigned int serial )
+{
+    struct detached_sync *detached;
+
+    LIST_FOR_EACH_ENTRY( detached, &detached_syncs, struct detached_sync, entry )
+    {
+        if (detached->process != process || detached->serial != serial) continue;
+        list_remove( &detached->entry );
+        release_object( detached->sync );
+        free( detached );
+        return STATUS_SUCCESS;
+    }
+    return STATUS_INVALID_PARAMETER;
+}
+
+void release_process_inproc_syncs( struct process *process )
+{
+    struct detached_sync *detached, *next;
+
+    LIST_FOR_EACH_ENTRY_SAFE( detached, next, &detached_syncs, struct detached_sync, entry )
+    {
+        if (detached->process != process) continue;
+        list_remove( &detached->entry );
+        release_object( detached->sync );
+        free( detached );
+    }
 }
 
 static int get_obj_inproc_sync( struct object *obj, int *type )
@@ -341,6 +449,19 @@ void abandon_inproc_mutexes( thread_id_t tid )
 {
 }
 
+void detach_inproc_sync( struct process *process, struct object *obj, unsigned int serial )
+{
+}
+
+unsigned int release_detached_inproc_sync( struct process *process, unsigned int serial )
+{
+    return STATUS_NOT_IMPLEMENTED;
+}
+
+void release_process_inproc_syncs( struct process *process )
+{
+}
+
 static int get_obj_inproc_sync( struct object *obj, int *type )
 {
     return -1;
@@ -363,3 +484,8 @@ DECL_HANDLER(get_inproc_sync_fd)
 
     release_object( obj );
 }
+
+DECL_HANDLER(release_inproc_sync)
+{
+    set_error( release_detached_inproc_sync( current->process, req->serial ) );
+}
diff --git a/server/object.h b/server/object.h
index 21f5ea8..ff369a0 100644
--- a/server/object.h
+++ b/server/object.h
@@ -255,6 +255,9 @@ extern struct inproc_sync *create_inproc_event_sync( int manual, int signaled );
 extern struct inproc_sync *create_inproc_semaphore_sync( unsigned int initial, unsigned int max );
 extern struct inproc_sync *create_inproc_mutex_sync( thread_id_t owner, unsigned int count );
 extern void abandon_inproc_mutexes( thread_id_t owner );
+extern void detach_inproc_sync( struct process *process, struct object *obj, unsigned int serial );
+extern unsigned int release_detached_inproc_sync( struct process *process, unsigned int serial );
+extern void release_process_inproc_syncs( struct process *process );
 extern void signal_inproc_sync( struct inproc_sync *sync );
 extern void reset_inproc_sync( struct inproc_sync *sync );
 
diff --git a/server/process.c b/server/process.c
index 287718a..130d2ca 100644
--- a/server/process.c
+++ b/server/process.c
@@ -808,6 +808,7 @@ static void process_destroy( struct object *obj )
     assert( !process->sigkill_timeout );  /* timeout should hold a reference to the process */
 
     close_process_handles( process );
+    release_process_inproc_syncs( process );
     set_process_startup_state( process, STARTUP_ABORTED );
 
     if (process->job)
@@ -1013,6 +1014,7 @@ static void process_killed( struct process *process )
     process->desktop = 0;
     cancel_terminating_process_asyncs( process );
     close_process_handles( process );
+    release_process_inproc_syncs( process );
     if (process->idle_event) release_object( process->idle_event );
     process->idle_event = NULL;
     assert( !process->console );
diff --git a/server/protocol.def b/server/protocol.def
index f1b7dee..c53894f 100644
--- a/server/protocol.def
+++ b/server/protocol.def
@@ -1383,6 +1383,7 @@ struct cpu_topology_override
 /* Close a handle for the current process */
 @REQ(close_handle)
     obj_handle_t handle;       /* handle to close */
+    unsigned int inproc_serial; /* if nonzero, keep the in-process sync (still used by another thread) under this serial */
 @END
 
 
@@ -1404,6 +1405,7 @@ struct cpu_topology_override
     unsigned int access;       /* wanted access rights */
     unsigned int attributes;   /* object attributes */
     unsigned int options;      /* duplicate options */
+    unsigned int inproc_serial; /* as for close_handle, when closing the source */
 @REPLY
     obj_handle_t handle;       /* duplicated handle in dst process */
 @END
@@ -4358,3 +4360,10 @@ enum fsync_type
     unsigned int shm_idx;
 @REPLY
 @END
+
+
+/* Stop keeping an in-process sync that close_handle / dup_handle kept: its last user is done.
+ * Appended after every other request so that existing request numbers stay the same. */
+@REQ(release_inproc_sync)
+    unsigned int serial;        /* serial given to close_handle / dup_handle */
+@END
mutex_abandon.c — the timed probe; build with x86_64-w64-mingw32-gcc -O2 -D__USE_MINGW_ANSI_STDIO=1 -o mutex_abandon.exe mutex_abandon.c (or i686-w64-mingw32-gcc for the 32-bit build); mutex_abandon.exe [close|keep|waitall] [iterations]
/* Timed version of the end of kernel32:sync test_mutex(), plus one corner case. Prints how long each step takes.
 *
 * Usage: mutex_abandon.exe [close|keep|waitall] [iterations]
 *   close (default): a thread owns a mutex and blocks; a second thread waits on the mutex; the mutex handle is
 *                    closed; the owner is killed with TerminateThread(). The waiter must get WAIT_ABANDONED.
 *   keep:            the same with the mutex handle kept open.
 *   waitall:         the mutex is unowned when its handle is closed, and two threads are blocked in wait-all calls
 *                    on it, each with its own unset event. Setting event A lets thread A take the mutex; A is then
 *                    killed; setting event B must give thread B the abandoned mutex.
 */
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

static HANDLE mutex, start_event, stop_event, event_a, event_b;
static LARGE_INTEGER freq, t0;

static double ms(void)
{
    LARGE_INTEGER t;
    QueryPerformanceCounter(&t);
    return (t.QuadPart - t0.QuadPart) * 1000.0 / freq.QuadPart;
}

static const char *abandoned(DWORD ret)
{
    return (ret >= WAIT_ABANDONED_0 && ret < WAIT_ABANDONED_0 + 2) ? " (abandoned)" : "";
}

static DWORD WINAPI owner_proc(void *arg)
{
    DWORD ret = WaitForSingleObject(mutex, INFINITE);
    printf("%9.1f ms  owner:  mutex wait returned %#lx\n", ms(), ret);
    SetEvent(start_event);
    ret = WaitForSingleObject(stop_event, INFINITE);
    printf("%9.1f ms  owner:  stop_event wait returned %#lx (must not happen)\n", ms(), ret);
    return 0;
}

static DWORD WINAPI waiter_proc(void *arg)
{
    DWORD ret = WaitForSingleObject(mutex, INFINITE);
    printf("%9.1f ms  waiter: mutex wait returned %#lx%s\n", ms(), ret, abandoned(ret));
    SetEvent(start_event);
    ret = WaitForSingleObject(stop_event, INFINITE);
    printf("%9.1f ms  waiter: stop_event wait returned %#lx\n", ms(), ret);
    return 0;
}

static DWORD WINAPI waitall_a_proc(void *arg)
{
    HANDLE objs[2] = { mutex, event_a };
    DWORD ret = WaitForMultipleObjects(2, objs, TRUE, INFINITE);
    printf("%9.1f ms  A:      wait-all on mutex + event A returned %#lx\n", ms(), ret);
    SetEvent(start_event);
    ret = WaitForSingleObject(stop_event, INFINITE);
    printf("%9.1f ms  A:      stop_event wait returned %#lx (must not happen)\n", ms(), ret);
    return 0;
}

static DWORD WINAPI waitall_b_proc(void *arg)
{
    HANDLE objs[2] = { mutex, event_b };
    DWORD ret = WaitForMultipleObjects(2, objs, TRUE, INFINITE);
    printf("%9.1f ms  B:      wait-all on mutex + event B returned %#lx%s\n", ms(), ret, abandoned(ret));
    SetEvent(start_event);
    ret = WaitForSingleObject(stop_event, INFINITE);
    printf("%9.1f ms  B:      stop_event wait returned %#lx\n", ms(), ret);
    return 0;
}

static int step(const char *what, DWORD ret, DWORD expect)
{
    printf("%9.1f ms  main:   %s %#lx (expect %#lx)%s\n", ms(), what, ret, expect, ret == expect ? "" : "  <-- FAILED");
    return ret != expect;
}

static void create_events(void)
{
    QueryPerformanceCounter(&t0);
    start_event = CreateEventW(NULL, FALSE, FALSE, NULL);
    stop_event = CreateEventW(NULL, FALSE, FALSE, NULL);
    event_a = CreateEventW(NULL, FALSE, FALSE, NULL);
    event_b = CreateEventW(NULL, FALSE, FALSE, NULL);
    mutex = CreateMutexA(NULL, FALSE, NULL);
}

static void close_events(void)
{
    CloseHandle(start_event);
    CloseHandle(stop_event);
    CloseHandle(event_a);
    CloseHandle(event_b);
}

static int run(int close_mutex)
{
    HANDLE owner, waiter;
    int failures = 0;

    create_events();
    owner = CreateThread(NULL, 0, owner_proc, NULL, 0, NULL);
    failures += step("owner started, start_event wait", WaitForSingleObject(start_event, 1000), 0);

    waiter = CreateThread(NULL, 0, waiter_proc, NULL, 0, NULL);
    failures += step("waiter blocked, start_event wait", WaitForSingleObject(start_event, 100), WAIT_TIMEOUT);

    if (close_mutex)
    {
        CloseHandle(mutex);
        failures += step("mutex handle closed, start_event wait", WaitForSingleObject(start_event, 100), WAIT_TIMEOUT);
    }

    printf("%9.1f ms  main:   TerminateThread(owner) -> %d\n", ms(), TerminateThread(owner, 0));
    failures += step("owner thread handle wait", WaitForSingleObject(owner, 5000), 0);
    failures += step("start_event wait (waiter got the mutex)", WaitForSingleObject(start_event, 5000), 0);

    SetEvent(stop_event);
    failures += step("waiter thread handle wait", WaitForSingleObject(waiter, 5000), 0);

    CloseHandle(owner);
    CloseHandle(waiter);
    if (!close_mutex) CloseHandle(mutex);
    close_events();
    return failures;
}

static int run_waitall(void)
{
    HANDLE a, b;
    int failures = 0;

    create_events();
    a = CreateThread(NULL, 0, waitall_a_proc, NULL, 0, NULL);
    b = CreateThread(NULL, 0, waitall_b_proc, NULL, 0, NULL);
    failures += step("A and B blocked, start_event wait", WaitForSingleObject(start_event, 100), WAIT_TIMEOUT);

    CloseHandle(mutex);   /* nobody owns the mutex here */
    failures += step("mutex handle closed, start_event wait", WaitForSingleObject(start_event, 100), WAIT_TIMEOUT);

    SetEvent(event_a);
    failures += step("event A set, start_event wait (A owns the mutex)", WaitForSingleObject(start_event, 1000), 0);

    printf("%9.1f ms  main:   TerminateThread(A) -> %d\n", ms(), TerminateThread(a, 0));
    failures += step("A thread handle wait", WaitForSingleObject(a, 5000), 0);

    SetEvent(event_b);
    failures += step("event B set, start_event wait (B got the abandoned mutex)", WaitForSingleObject(start_event, 5000), 0);

    SetEvent(stop_event);
    failures += step("B thread handle wait", WaitForSingleObject(b, 5000), 0);

    CloseHandle(a);
    CloseHandle(b);
    close_events();
    return failures;
}

int main(int argc, char **argv)
{
    const char *mode = argc > 1 ? argv[1] : "close";
    int iterations = argc > 2 ? atoi(argv[2]) : 1, i, failures = 0;

    setvbuf(stdout, NULL, _IONBF, 0);
    QueryPerformanceFrequency(&freq);
    if (strcmp(mode, "close") && strcmp(mode, "keep") && strcmp(mode, "waitall"))
    {
        printf("usage: mutex_abandon.exe [close|keep|waitall] [iterations]\n");
        return 2;
    }
    printf("mode: %s, %d iteration(s)\n", mode, iterations);
    for (i = 0; i < iterations; i++)
    {
        printf("--- iteration %d\n", i + 1);
        if (!strcmp(mode, "waitall")) failures += run_waitall();
        else failures += run(!strcmp(mode, "close"));
    }
    printf("%d failed step(s)\n", failures);
    return failures;
}
Jjegglest 2026-10-02 github

@Elthz Your crash is the one analysed above, in every file you attached:

  • Both minidumps (crash_data.zip and the 2026-09-22 report) record an access violation at Retail.exe+0x2158FEE on the resFILE_LOADER thread with rcx=3, the signature from my first comment.
  • Two of the three Proton logs have the matching dispatch_exception code=c0000005 ... addr=0000000142158FEE line (OP2 at 6580 s, Siege at 1386 s); OP1 ended without a captured fault.
  • Same game build (14.2, 1339092/1344629), kernels 7.2.3, 7.2.4 and 7.2.6, ntsync active.

So it is not EAC, the GPU or memory. The error 1726 / RPC_S_SERVER_UNAVAILABLE lines appear only after the fault, when the services process loses its connection to the dying game, and the vkd3d-proton "view map pressure" warnings show up in all your logs long before the crash (and in mine). The crash dialog staying up while the game carries on for a while is what it looks like when the file-loader thread dies.

What it is: the game waits on a future with a single SleepConditionVariableCS(INFINITE), and on Wine that wait returns early, because a wake that races a zero-timeout WaitOnAddress() from the game's allocator leaves a stale thread alert behind. The read callback then writes into a stack frame that no longer exists. On Windows the same wait does not return early: 0 early returns in 100,000 on Windows 11 against 13% on Wine, same program, same machine. Windows' own implementation takes the racing wake instead of leaving it pending, and this game has run on that for a year. It crashes here because Wine behaves differently from Windows at that spot, and that is what needs fixing. The fix is small (patches in my comments above) and has given me 9.4 hours without a crash so far.

What helps today:

  • A 7.1 kernel. Several people here report the crash stops on 7.1.x; it arrived with 7.2, which makes the race far more frequent, though what changed in 7.2 hasn't been pinned down. On Arch that means a 7.1 package from the archive, or an LTS kernel if one is still on 7.1.
  • The Wine-side fix, if you build Proton Experimental's Wine yourself: the ntdll patch in my 2026-09-29 comment plus the server patch in the comment just above (both the 64- and 32-bit unix ntdll have to be rebuilt, see the notes there). I don't have it in a form I can hand out.
  • I've also reported it to Saber (ticket 12458 on the Focus tracker, https://community.focus-entmt.com/focus-entertainment/space-marine-2/bugs/12458), since a loop around that wait would make the game immune to it. Adding your report there doesn't hurt. But the behaviour that differs from Windows is Wine's, and the patches above are the fix for that.
Jjegglest 2026-10-02 github

Filed the mutex abandonment bug upstream as https://bugs.winehq.org/show_bug.cgi?id=60417 (Wine, wineserver), with the analysis, the Windows measurements and the fix approach in prose; the patches above are the prototype. Wine bug 60397 remains the one for the stale thread alert behind the crash.

EElthz 2026-10-02 github

@jegglest thank you for the answer, hopefully your fix is implemented swiftly in wine/proton.

JJpokul 2026-10-03 github

@jegglest I compiled the prototype with the 2 fixes you posted with Valve's wine, and it fixed the crashing for me. I also compiled with the 1st fix only, which also worked. I played with both for several hours without restarting the game and without any crashes, while earlier they happened at a rate of around 1-3 per hour.

May I share the prototype Proton fix with others to download, put in the right folder, and have it available as a Proton compatibility tool, or would you prefer to keep it under wraps until it's implemented officially? I sent you access to the repository.

JJMarcosHP 2026-10-03 github

@jegglest please open a PR here on proton repo or valve's wine for these 2 fixes.

Kkisak-valve maintainer 2026-10-03 github

In general, any changes that can go to upstream wine, should go upstream first, and https://gitlab.winehq.org/wine/wine/-/wikis/Developer-FAQ#can-i-contribute-code-generated-by-a-large-language-model-llm-tool should be taken into consideration while doing that. Over time, we want the difference between upstream wine and Proton to shrink, so that Proton remains maintainable.

JJMarcosHP 2026-10-03 github

The developers will not take any action, even after the patches fixed both issues and the theory proposed by the LLM's diagnosis was correct, contrary to what they assumed without checking it or taking the time to verify it on their own, as users have done in this case.

So what alternative do we have? I'm sorry, but their arguments sound very poor to me compared to what these users have done to contribute.

If anyone has a different opinion, I'm open to hearing it.

Jjegglest 2026-10-03 github

@Jpokul yes, you can share the prototype proton, no problem! The first patch fixes space marine 2. The second patch is an issue I just stumbled across when vetting the first patch, a regression introduced with ntsync, unrelated to space marine 2 but... it seemed like an issue in need of being fixed.

@kisak-valve I have provided the bug report, reasoning, and code that can independently reproduce the problems without having to run Space Marine 2, to Wine. I have read the guidelines, LLMs are only banned from code contributions, they aren't banned from discussion or diagnosis. They can implement a fix without using an LLM if they choose. But so far, we don't have real engagement. Like @JMarcosHP, I'm not sure where to take it from here.

JJpokul 2026-10-03 github

I made the compiled build available at https://github.com/Jpokul/prototype_SM2_proton_fix_patch14-15

Instructions on how to use it are on the repository page.

@Erfboom, it's named SM2 fix, but other games can be run with it as well if you haven't compiled it yourself.

MML0B 2026-10-03 github

I made the compiled build available at https://github.com/Jpokul/prototype_SM2_proton_fix_patch14-15

Instructions on how to use it are on the repository page.

@Erfboom, it's named SM2 fix, but other games can be run with it as well if you haven't compiled it yourself.

Thanks! I've tried a session 3+ hours, it works!

JJMarcosHP 2026-10-03 github

I made the compiled build available at https://github.com/Jpokul/prototype_SM2_proton_fix_patch14-15

Instructions on how to use it are on the repository page.

@Erfboom, it's named SM2 fix, but other games can be run with it as well if you haven't compiled it yourself.

Thanks for your hard work ♥️, I'll try it now.

Xx5f3759df 2026-10-03 github

So, with PROTON_NO_NTSYNC=1 there are no crashes? Does anybody try this?

nvm, doesn't work

RRhombic-Drive 2026-10-04 github

I made the compiled build available at https://github.com/Jpokul/prototype_SM2_proton_fix_patch14-15

Instructions on how to use it are on the repository page.

@Erfboom, it's named SM2 fix, but other games can be run with it as well if you haven't compiled it yourself.

Thank you @Jpokul and @jegglest for your work. Played for several hours including 25 waves of siege, no crashes.

CChiefZeng 2026-10-05 github

I made the compiled build available at https://github.com/Jpokul/prototype_SM2_proton_fix_patch14-15

Instructions on how to use it are on the repository page.

@Erfboom, it's named SM2 fix, but other games can be run with it as well if you haven't compiled it yourself.

By the emperor, thank you so much this finally fixed it. I played 4 hours non-stop of operations and 15 waves of siege without a single crash when previously I would crash within an hour.

66ty7er 2026-10-05 github

I made the compiled build available at https://github.com/Jpokul/prototype_SM2_proton_fix_patch14-15

Instructions on how to use it are on the repository page.

@Erfboom, it's named SM2 fix, but other games can be run with it as well if you haven't compiled it yourself.

Sadly, this is using FSR3 on Navi32/RDNA3. Override with SLO didn't work. Any chance this gets FSR4 support?

Jjegglest 2026-10-05 github

The goal is for proton to accept the patches, which will then be adopted by the proton derivatives.

IIchnafi 2026-10-05 github

I would like to also confirm, that this patched Proton version is working. Also Played nearly 3 hours without any special start-parameters, without any issues.

To bad the Imperator condemns all AI as heresy.

CCMDR-Ryoohk 2026-10-06 github

Thank you so much, did 2 hours and no crashes so far.

Fedora 44 7.2.8-200.fc44.x86_64

Tthecorvidad 2026-10-06 github

Same here, I played a total of 6h, no crashes.

Also Fedora 44, Linux 7.2.8-200.fc44.x86_64, KDE on Wayland

Ddefaultuser321 2026-10-06 github

Unfortunately it did not help to fix the crashes for me.
PikaOS 4 x86_64
Linux 7.2.6-pikaos
GNOME 51.0 (Wayland)

Jjegglest 2026-10-06 github

@defaultuser321 if you can supply crash info like @Elthz did above, we can figure out what's going on, probably.

JJpokul 2026-10-06 github

As a reminder:
If a game crashes, some logs should be generated automatically to
~/.local/share/Steam/steamapps/compatdata/2183900/pfx/drive_c/users/steamuser/AppData/Local/Saber/Space Marine 2/client/reports/

You can also run the game with PROTON_LOG=1 %command% set in launch options before launching the game and before the crash occurs, and then log will be saved in the home directory.

Ddefaultuser321 2026-10-06 github

The path "/mnt/Data/SteamLibrary/steamapps/compatdata/2183900/pfx/drive_c/users/steamuser/AppData/Local/Saber/Space Marine 2/client/reports" exists, there's 17 report folders (latest are report_2026_10_06_20_19_05_pid364 & report_2026_10_06_20_19_23_pid364), but all folders are empty.
I presume that log is not created since game does not crash with any error, it just freeze and system offers termination after some time when game's not responding.
Proton log attached -> 104MB unpacked / 5MB packed

steam-2183900.zip

Let me know if you need any additional info.

JJpokul 2026-10-06 github

Sadly, this is using FSR3 on Navi32/RDNA3. Override with SLO didn't work. Any chance this gets FSR4 support?

@6ty7er If it's something you absolutely need, you could roll back your Linux kernel to an LTS version with kernel 7.1 or earlier, before they changed something that is contributing to this bug. Or maybe even kernel 6 that is used in Debian.

As for me, I'm an armchair programmer who compiled this solution for people to have an easy way to play without doing anything complicated, and to prove the LLM fix works (and to have people help with finding bugs if it doesn't). The best solution would be to have this fix implemented upstream, or better yet - one made by a knowledgeable developer.

I'm also not skilled or knowledgeable enough to include additions without a significant time investment.

https://github.com/Jpokul/prototype_SM2_proton_fix_patch14-15 is a build compiled from https://github.com/ValveSoftware/Proton at commit adea6cb.

From what I gather, it should include FSR4 support, but I don't know how to verify it or if it works with SM2. You may try using the launch option PROTON_FSR4_UPGRADE=1; if it works for you, great. If it doesn't, I don't know how to do it. I checked SM2, and it doesn't clearly communicate which FSR it's using.

If somebody doesn't trust my compilation or wants functionality outside what the aforementioned Proton offers, compiling it yourself using the fix written in https://github.com/ValveSoftware/Proton/issues/8072#issuecomment-5903294489 should do the trick. It's highly encouraged to verify the code yourself first.

As for my build, I also used another fix: https://github.com/ValveSoftware/Proton/issues/8072#issuecomment-5943056744, but that one isn't required.

EDIT: After some investigating, it seems FSR4 doesn't work on Proton Experimental with Radeon 9000 series. In that case, it won't work with the prototype fix either.

Jjegglest 2026-10-07 github

@defaultuser321 Thanks, the log helps. This is a different problem from the crash in this issue:

  • Nothing crashed. The crash this issue is about is an access violation (code=c0000005 at Retail.exe+0x2158FEE on the resFILE_LOADER thread). Your log has none, only the usual debug-print and thread-naming exceptions. So the patches in the prototype have nothing to fix here.
  • The game's main thread stopped at 21:00:02 your time (log time 94619.356, matched to MangoHud's timestamps). For the 40 minutes before, that thread called the GPU-statistics stubs (NtGdiDdDDIQueryStatistics) every frame, about 60 times a second, with no gap over 2 s after the first minute. At 21:00:02 it rescanned HID devices: the two hid_joystick_device_try_open device usage 000c:0001 / ff00:0001 not implemented! lines are dinput skipping two devices that aren't gamepads, the same two it skipped at startup. The thread never logged anything again.
  • The rest of the game kept going. Two other game threads went on polling memory statistics every 100 ms until you force-quit about 33 s later, so the process and Wine's server were still working. There are no err:sync ... wait timed out lines (Wine prints one after 5 s on a critical section) and no vkd3d-proton errors.

In your log the game scans for input devices twice at startup and then only once more, at 21:00:02, two seconds after the top of the hour. Games usually rescan when Windows reports a device change, so something probably happened on your system at 21:00: a scheduled job (backup, snapshot, updater), or a controller, headset, dongle or other USB/Bluetooth device connecting, disconnecting or waking up. The main thread got stuck in that rescan or in whatever the game did right after it.

I don't see how either patch could cause this. The only new waiting in the ntdll change happens when a timed wait times out at the same moment a wake arrives: it then takes that wake, which is already on its way, instead of leaving it pending. The mutex change only matters when a thread dies while owning a mutex, or when a mutex handle is closed while another thread of the same process is still waiting on it, and nothing like that happens in the rescan. Testing without the patches is the way to be sure, though.

What would narrow it down:

  1. What did you get before the prototype? Was it this same freeze, or the "Unhandled exception happened" window? The report_* folders are always empty (the game makes one at every launch; mine are empty too). A crash leaves crash_data.zip directly in reports/, and its date would tell us whether you ever had the crash from this issue.
  2. Do your freezes line up with anything? The top of the hour, a controller or headset turning on/off or going to sleep, a USB device, a monitor switching off or changing input?
  3. The system journal for that minute, if it's still there (add sudo if it only shows your own user's messages):
    journalctl --since "2026-10-06 20:59:50" --until "2026-10-06 21:00:40" -o short-precise > ~/sm2-journal.txt
    
    It covers USB/Bluetooth, timers and cron jobs, and amdgpu if the GPU had hung. Look it over for anything private before attaching it.
  4. A session or two on stock Proton Experimental. If it freezes the same way there, the patches aren't involved.
  5. If it freezes again, run this in a terminal before you force-quit. It only reads /proc and attaches nothing to the game, so it's fine with EAC:
    pid=$(pgrep -n -f 'Space Marine 2 - Retai[l]')
    top -H -b -n 2 -d 2 -w 200 -p "$pid" > ~/sm2-freeze-top.txt
    ps -L -o tid,stat,wchan:32,comm -p "$pid" > ~/sm2-freeze-threads.txt
    for p in $(pgrep -f 'winedevice.ex[e]'); do ps -L -o tid,stat,wchan:32,comm -p "$p"; done >> ~/sm2-freeze-threads.txt
    
    If you can, also use PROTON_LOG=+hid,+mountmgr %command% instead of PROTON_LOG=1 for that session. It adds HID device opens and drive changes to the log. With a controller connected the log gets much bigger, but it compresses well.
Ddefaultuser321 2026-10-07 github

logs.zip

@jegglest
1. What did you get before the prototype? Was it this same freeze, or the "Unhandled exception happened" window? The report_* folders are always empty (the game makes one at every launch; mine are empty too). A crash leaves crash_data.zip directly in reports/, and its date would tell us whether you ever had the crash from this issue.

  • I tried to use several Proton versions over last maybe 4 - 5 weeks, ProtonGE-Latest, ProtonCachyOS-latest, Proton 9.x, Proton 10.x, Proton 11.x, Proton Experimental, ProtonCachyOS-Latest V3. All provided slightly different results in terms of stability, error reporting and number of crashes. Some would crash with game's error report window (many times if I ignore the crash report window the game would run "normaly" few minutes longer and then it'll freeze), some would simply freeze the game as I mentioned in last comment. The cadence of crashes was varied between like 5 minutes up to several hours of play time. Very rarely the game crashed in the lobby or game menu (maybe 2 or 3 times from at least several tens of crashes over mentioned period of time).
    2. Do your freezes line up with anything? The top of the hour, a controller or headset turning on/off or going to sleep, a USB device, a monitor switching off or changing input?
  • Nope, my machine is running pretty much 24/7 without connecting any peripherals except occasional connecting of bluetooth headphones (but I haven't used those for weeks). I have connected one external SSD via USB-C port, like permanently for system backups with Timeshift. But backups are scheduled to 19:00 every day and crashes do not correspond with this time at all. I do not have any controller, any other USB device or another monitor. Machine is as bare as possible.
    3. The system journal for that minute, if it's still there (add sudo if it only shows your own user's messages): journalctl --since "2026-10-06 20:59:50" --until "2026-10-06 21:00:40" -o short-precise > ~/sm2-journal.txt
  • I will check system journal when I get home from work
    4. A session or two on stock Proton Experimental. If it freezes the same way there, the patches aren't involved.
  • I tried Proton experimental already, the game crashes on any Proton version, even on Proton:GE-Proton11-1, which was rock solid like 3 months ago.
    5. If it freezes again, run this in a terminal before you force-quit. It only reads /proc and attaches nothing to the game, so it's fine with EAC: pid=$(pgrep -n -f 'Space Marine 2 - Retai[l]') top -H -b -n 2 -d 2 -w 200 -p "$pid" > ~/sm2-freeze-top.txt ps -L -o tid,stat,wchan:32,comm -p "$pid" > ~/sm2-freeze-threads.txt for p in $(pgrep -f 'winedevice.ex[e]'); do ps -L -o tid,stat,wchan:32,comm -p "$p"; done >> ~/sm2-freeze-threads.txt If you can, also use PROTON_LOG=+hid,+mountmgr %command% instead of PROTON_LOG=1 for that session. It adds HID device opens and drive changes to the log. With a controller connected the log gets much bigger, but it compresses well.
  • I will try that later today

All requested logs in attachment -> 96MB unpacked / 4,8MB packed

EDIT: The freeze landed within a second of the Timeshift cron job at exactly 21:00:01. So I was wrong with 19:00 time of Timeshift backup. I am no expert but could it be some bug in regard to cron itself? And if it is cron bug, why is everything except Space Marine 2 working without any issue?

Ddefaultuser321 2026-10-07 github

Well, I disabled cron for the test and set Space Marine 2 to use latest Proton CachyOS V3 and game is running buttery smooth for 4 hours now. Looks like for some reason cron or cron related action was the cause of my issues. Strangely game is now working even without the fix you created.
Anyway, thank you for helping me find out the problem.

JJMarcosHP 2026-10-07 github

Well, I disabled cron for the test and set Space Marine 2 to use latest Proton CachyOS V3 and game is running buttery smooth for 4 hours now. Looks like for some reason cron or cron related action was the cause of my issues. Strangely game is now working even without the fix you created.
Anyway, thank you for helping me find out the problem.

Have you recreated your proton prefix before switching to proton-cachyos again?

How do you disabled Cron?

Ddefaultuser321 2026-10-07 github

@JMarcosHP

Well, I disabled cron for the test and set Space Marine 2 to use latest Proton CachyOS V3 and game is running buttery smooth for 4 hours now. Looks like for some reason cron or cron related action was the cause of my issues. Strangely game is now working even without the fix you created.
Anyway, thank you for helping me find out the problem.

Have you recreated your proton prefix before switching to proton-cachyos again?

How do you disabled Cron?

"sudo systemctl stop cron
systemctl is-active cron"
This will just pause cron and verify if it is inactive (effective until restart of the system or manual activation)
And yes, I recreated my original Proton prefix I uses some time ago.
"ENABLE_LAYER_MESA_ANTI_LAG=1 PROTON_FSR4_UPGRADE=1 PROTON_MLFG_UPGRADE=1 mesa_glthread=true WINE_VK_USE_SYNC2=1 WINE_SYNC_USE_FUTEX_WAITV=1 %command% -skip-launcher"

But of course, running the game for several hours without the crash does not necessarily mean the problem with the game is not present. It simply might occur less often. The time will tell.

Jjegglest 2026-10-08 github

It's going to take time for these issues to be addressed upstream, we need more people testing the patches with other games, not just space marine 2.

I've forked proton experimental https://github.com/jegglest/proton-je and submitted a PR to add it to ProtonPlus.

66ty7er 2026-10-08 github

@6ty7er If it's something you absolutely need, you could roll back your Linux kernel to an LTS version with kernel 7.1 or earlier, before they changed something that is contributing to this bug. Or maybe even kernel 6 that is used in Debian.

Yes, this is something I need. I waited since 7800XT release for FSR4. FSR3 is really ugly.

As for me, I'm an armchair programmer who compiled this solution for people to have an easy way to play without doing anything complicated, and to prove the LLM fix works (and to have people help with finding bugs if it doesn't). The best solution would be to have this fix implemented upstream, or better yet - one made by a knowledgeable developer.

I really appreciate this, but I'm asking myself why there is no FSR4? If you don't know the difference, you should look it up.

Ddefaultuser321 2026-10-08 github

@jegglest

It's going to take time for these issues to be addressed upstream, we need more people testing the patches with other games, not just space marine 2.

I've forked proton experimental https://github.com/jegglest/proton-je and submitted a PR to add it to ProtonPlus.

Let me know if you need any help with testing. When I got time I can help with pretty much anything. Just please bear in mind that I have no programming background at all, so any complex request might need more precise explanation.

JJpokul 2026-10-08 github

From what I read about FSR4 - it is included in the proton experimental, but there is a bug that fails to properly enable FSR 4 on RDNA 4 (Radeon 9000) hardware or certain games because the bundled FSR 4 dynamic-link library (amdxcffx64.dll) restricts execution strictly to RDNA 3 GPUs (Radeon 7000), causing it to fall back to FSR 3.

Jjegglest 2026-10-08 github

@defaultuser321 yes, that would be great! I'm quite confident the patches fix space marine 2. What I'm most interested in is if anyone can find a game that the patches break.

proton-je now has FSR 4 support. @Jpokul it was harder than what you're describing but I mainly cherry picked patches that already exist. Hopefully, that will make proton-je more tolerable to use for testing the fixes.

When it is added to ProtonPlus it should be easier for everyone to install it and keep it updated. In the mean time:

https://github.com/jegglest/proton-je#installing-a-build

EErfboom 2026-10-08 github

@jegglest I can also help with testing. I added your patches to proton GE lastest, compiled, and ran briefly with Control Resonance and it did not cure my crash on an rtx3080 that pyroveil fixes which most likely means it won't help Alan Wake 2 either. I have some free time coming up so I'll confirm I have the same error or a similar one as Space Marine 2, and provide more details to see if the patch even applies. Could have sworn I had the same Xid109 plus waiting for sephamore error, but I'll do my due diligence and report back. Might be entirely separate.

Jjegglest 2026-10-09 github

@Erfboom thanks! Yeah, any feedback on any games is great, even if the feedback is, no perceivable effect.

PPrimeAesthetic 2026-10-10 github

Just wanted to say Thank you, the fix absolutely fixed the SM2 crashing bug for me. You guys are doing god's work and for the emperor! :)

Jjegglest 2026-10-11 github

There is a new build: proton-je-11.0-20261001-3, the patches had a regression which showed up when I played Foundry for a little bit. Grab the new build, or update your own locally patched proton: https://github.com/jegglest/proton-je#installing-a-build

Why this release: proton-je-11.0-20261001-1 and -2 abort any game once it has about 3300 handles open at once and waits on one of the higher ones. Patch 5 made the in-process sync cache entry 20 bytes, the cache mapped its 64K blocks at the entries' exact size, 65520 bytes, and Wine's anon_mmap_alloc() asserts that its size is a multiple of the page size: the game disappears or freezes, and the only trace is one line in Steam's console log, virtual.c:408: anon_mmap_alloc: Assertion `!(size & host_page_mask)' failed. Found with Foundry during an autosave. The cache now maps whole 64K blocks (details); nothing else changed since -2. Please replace -1 and -2 with this build.

Ddlpnd 2026-10-12 github

@jegglest confirming, using proton-je, game did not crash once in the last 14 hours

Related threads

Proton versions

Launch options

Launch lines

Upstream links

DLLs

Error codes