protonscr

Steam isolates from system `/lib`, but keeps SDL config environment variables

steamopen runtime
ValveSoftware/steam-for-linux#13361 · opened 2026-06-30 by clarfonthey · updated 2026-07-09 · 3 comments · github
4 matching comments, n / p to jump
Cclarfonthey 2026-06-30 github

Your system information

  • Steam client version (build number or date): 2026-06-29 (no idea how to check this, that's the current date)
  • Distribution (e.g. Ubuntu): Arch Linux
  • Opted into Steam client beta?: No
  • Have you checked for system updates?: Yes
  • Steam Logs: steam-logs.tar.gz
  • GPU: AMD Radeon RX 6800 XT (RADV NAVI21)

Please describe your issue in as much detail as possible:

I have a few SDL config variables defined in my environment to ensure up-to-date SDL for other applications I run outside of Steam, particularly:

  • SDL_VIDEO_DRIVER
  • SDL_DYNAMIC_API (SDL2)
  • SDL3_DYNAMIC_API (SDL3)

It's clear that the steam runtime might sometimes take these variables into account, looking at the source: https://gitlab.steamos.cloud/steamrt/steam-runtime-tools/-/blob/main/bin/launch-options.py

However, Steam itself does not seem to remove these variables from the environment when it runs, despite the fact that it isolates the environment to remove access to system libraries. So, when adding variables like SDL_DYNAMIC_API to the environment, upon launch, Steam shows dialogue boxes and writes to the log with messages like:

Couldn't load an overriding SDL library. Please fix or remove the SDL_DYNAMIC_API environment variable. Using the default SDL.

And this additionally happens for games run via the Steam runtime which use SDL internally, where these dialogue boxes might show up multiple times.

Since Steam is already aware of the various environment variables SDL uses, as evidenced by the Runtime code, it should remove these variables from the environment before it starts, not just when the Steam Runtime is specifically configured to do so with separate scripts.

It's worth mentioning that these dialogue boxes appear to block SDL from starting up until resolved, but will continue to work as normal after that. Steam does not appear to be blocked by this dialogue box (although I wonder what is blocked by it…) but games that use SDL are blocked until dialogue boxes are resolved, sometimes requiring multiple dismissals (presumably because SDL is loaded multiple times for Steam itself, the Runtime, Proton, and the game, for example).

Steps for reproducing this issue:

SDL_VIDEO_DRIVER=wayland,x11 SDL3_DYNAMIC_API=$(realpath /usr/lib/libSDL3.so) SDL_DYNAMIC_API=$(realpath /usr/lib/libSDL2.so) steam

(note: SDL_VIDEO_DRIVER is harmless here because both do work, but the dynamic API variables definitely don't, and it's clear from the runtime that Steam may want to turn off all SDL variables if it wants to control the version of SDL available in the runtime)

Relevant docs

Ssmcv 2026-07-06 github

There are two schools of thought regarding environment variables:

  • the user is always right (even if they're wrong) and user-set environment variables should be an override, even if they will break things;
  • or, the runtime should try to drop/ignore environment variables that are going to be a problem and do its best to make games work, even if that means overriding user configuration

Obviously those two are contradictory and there's no way Steam can do both, so whatever it does, someone is going to be disappointed.

The Steam Runtime has mostly gone with the "user is always right" approach, except in a few specific cases where setting environment variables is functionally necessary to make its containers work. For example, this means that the SDL team can (and do!) use SDL_DYNAMIC_API to force-load a locally-built SDL into Steam games while testing bug fixes.

However, this means that it's up to the user to limit workarounds to the narrowest possible scope where they'll be effective, rather than applying them indiscriminately. Workarounds usually have some important down-sides - if it was safe for them to be the default, they'd be the default already - so the safest way to use them is minimally.

Couldn't load an overriding SDL library. Please fix or remove the SDL_DYNAMIC_API environment variable. Using the default SDL.

For extra warning messages, if you try using Proton/Wine to launch a Windows game that happens to use the Windows version of SDL (Tiny Tina's Assault on Dragon Keep is one that I often use for testing), it will try and fail to load the Linux SDL from $SDL_DYNAMIC_API as though it was a Windows/PE DLL (as well as trying to load the overridden Linux SDL into winedevice.exe to implement gamepad support, which will succeed if given a suitable value). This is because Wine doesn't distinguish between "Linux-world" and "Windows-world" environment variables.

SDL3_DYNAMIC_API=$(realpath /usr/lib/libSDL3.so) SDL_DYNAMIC_API=$(realpath /usr/lib/libSDL2.so)

Why are you setting these environment variables? I would guess that the most likely reason is as a workaround for a non-Steam game that vendors its own outdated copy of SDL (statically linked, or via LD_LIBRARY_PATH or RUNPATH or similar) which you want to replace with your system copy?

If you're doing this as a workaround at that level, I'd recommend setting it in a wrapper script for the individual game(s), instead of globally. Similarly, for Steam games, I'd recommend using Steam's Launch Options feature for individual games that need workarounds, instead of applying workarounds to all of Steam and its recursive process tree, or to the whole OS.

This is also not going to work for 32-bit games, which need to use a 32-bit SDL (if available, it would be in /usr/lib32 on Arch). This word-size issue is why the steam-runtime-launch-options debugging tool doesn't actually set SDL_DYNAMIC_API directly: instead, it sets STEAM_COMPAT_RUNTIME_SDL2 or STEAM_COMPAT_RUNTIME_SDL3, which result in a lower-level component setting SDL_DYNAMIC_API or SDL3_DYNAMIC_API to paths that use the ${LIB} or ${PLATFORM} dynamic string tokens to achieve some limited architecture-independence.

SDL_VIDEO_DRIVER=wayland,x11

Similarly, I would not recommend this. In SDL versions where the default is to prioritize X11 (via Xwayland) higher than native Wayland, that default is there for a reason: if native Wayland was always a better choice than X11 via Xwayland, then the SDL team would already have made it the default.

For Steam users in particular, gameoverlayrenderer.so only works as intended when using X11/GLX, not when using X11/EGL or Wayland/EGL (#8020), so forcing native Wayland to be prioritized will break features like Steam Input.

Fflibitijibibo 2026-07-06 github

Similarly, I would not recommend this. In SDL versions where the default is to prioritize X11 (via Xwayland) higher than native Wayland, that default is there for a reason: if native Wayland was always a better choice than X11 via Xwayland, then the SDL team would already have made it the default.

To clarify: Upstream SDL does default to Wayland, but the Steam runtime switches this around as part of working around #8020.

Separately: There are cases where the outer environment variables can clash with containers; for example, an environment may define SDL_VIDEO_DRIVER=wayland but in a Wine environment this doesn't make sense since the only valid driver there is windows. Another example is DOTNET_ROOT which can be defined for a Linux-native .NET SDK installation, but a Wine prefix will inherit this and break any prefix's Windows .NET SDK installation.

I guess the issue boils down to "is there a difference between platform-specific variables and cross-platform variables," which is frustrating just to write down let alone answer, but that's probably because it deserves some kind of answer, no matter how fussy or selective it is at first.

EDIT: Wine Bugzilla report for DOTNET_ROOT https://bugs.winehq.org/show_bug.cgi?id=55544

Ssmcv 2026-07-09 github

There are cases where the outer environment variables can clash with containers; for example, an environment may define SDL_VIDEO_DRIVER=wayland but in a Wine environment this doesn't make sense

Wine isn't a container, but yes: a more general description of the issue is that environment variable inheritance can easily cause problems whenever the transition between a higher layer and a lower layer results in changing the execution context so that the environment variable's value is no longer appropriate.

In the Steam Runtime's containers, the change that invalidates (some) environment variables is that the meaning of paths below /lib* and /usr has changed. In Wine, the change that invalidates (some) environment variables is that paths, driver names, etc. are being interpreted as though they were for a Windows program. And when you run a game under Proton, that's Wine inside the Steam Runtime, so both of those problems can happen at the same time.