“XDG_RUNTIME_DIR is invalid or not set” on Raspberry Pi 5
Updated Aug 23, 2024
Recently, while running Rasperry Pi OS on my sparkly new Raspberry Pi 5 I ran into an issue running the MPV media player. I had created two user accounts, one to log into the Pi with and another to run my program under. I then encountered a strange problem with MPV. MPV output the following error to the console:
error: XDG_RUNTIME_DIR is invalid or not set in the environment.
error: XDG_RUNTIME_DIR is invalid or not set in the environment.
Opening /dev/dri/renderD128 failed: Permission denied
error: XDG_RUNTIME_DIR is invalid or not set in the environment.
error: XDG_RUNTIME_DIR is invalid or not set in the environment.
Opening /dev/dri/renderD128 failed: Permission denied
error: XDG_RUNTIME_DIR is invalid or not set in the environment.
error: XDG_RUNTIME_DIR is invalid or not set in the environment.
libEGL warning: failed to open /dev/dri/renderD128: Permission denied
libEGL warning: failed to open /dev/dri/card0: Permission denied
So… what the heck is that? Can this new user not output to my screen? >.<
Looking up the most prominent of those errors, it looks like XDG_RUNTIME_DIR is a user-specific directory that gets used by PAM during the user authorization process. Since I only use this second user account for to run the application, the user never actually uses PAM, so this directory never actually gets created. Even so, apparently I still need to have this directory to run “desktoppy” things. Yes, “desktoppy” is clearly a word. Don’t question it.
So, I need a user-specific one of these directories. Since the directory is DELETED every time the system reboots, we need a reliable way to create that directory during system boot that doesn’t rely on PAM. For my purposes, I used a SystemD script: sudo nano /home/user2/create-xdg-runtime-dir.service
[Unit]
Description=Create XDG_RUNTIME_DIR for user2
After=local-fs.target
[Service]
Type=oneshot
ExecStart=/bin/mkdir -p /run/user/1001
ExecStart=/bin/chown 1001:1001 /run/user/1001
ExecStart=/bin/chmod 700 /run/user/1001
[Install]
WantedBy=multi-user.target
In the above script, take note of the chown
command: That is specifically using your user’s user id and group id. If you’re not sure what the ID’s for your user are, just run the following command:
id user2
Next, once the file has been created, move it to your systemD directory:
sudo cp /home/user2/create-xdg-runtime-dir.service /etc/systemd/system/
Then configure it to start at bootup with the following commands:
sudo systemctl enable create-xdg-runtime-dir.service
sudo systemctl start create-xdg-runtime-dir.service
Last, run the following command to add the XDG_RUNTIME_DIR environment variable to your user’s BASH profile:
echo "export XDG_RUNTIME_DIR=/run/user/$(id -u)" >> ~/.bashrc
After that we should be all set when it comes to the XDG_RUNTIME_DIR variable error message.
Next we have the permission denied issues. I tested the command with my first user, and found that the command ran just fine. So, there’s clearly some kind of difference between my first user (the one that I created during system install) and my second user (the one that I created to run my app under). It’s likely that these directories were created to be used by users of the system, so I’m probably dealing with some group permissions that aren’t dished out by default. Let’s check those.
$ ls -al /dev/dri/renderD128
crw-rw----+ 1 root render 226, 128 Mar 8 16:45 /dev/dri/renderD128
$ ls -al /dev/dri/card0
crw-rw----+ 1 root video 226, 0 Mar 8 16:45 /dev/dri/card0
Now lets see what groups my two users are members of:
sudo groups myuser
myuser : myuser adm dialout cdrom sudo audio video plugdev games users input render netdev spi i2c gpio
sudo groups user2
user2 : user2
Well, there it is. Clearly I never added my new user to the “render” or “video” groups, because I didn’t know I needed to. Let’s add “user2” to those groups I guess:
sudo usermod -a -G render,audio,video user2
Boom. Everything works smooth like butter. Wonder what other groups I might need to add “user2” to in order to make sure things work properly…? Rather than just blindly copying user ALL permissions from one user to the next, I’d rather just give a user access to what they need to run and nothing more.
Hope this helps someone.