obsidian/wiki/concepts/docker-lxc-gpu-device-node-mismatch.md
2026-05-09 17:44:30 +01:00

4 KiB

title aliases tags sources created updated
Docker LXC GPU Device Node Mismatch — renderD128 vs renderD129
docker-gpu-device-node
lxc-gpu-passthrough-mismatch
renderd-mismatch
docker
lxc
proxmox
gpu
jellyfin
homelab
hardware
debugging
daily/2026-05-03.md
2026-05-03 2026-05-03

Docker LXC GPU Device Node Mismatch — renderD128 vs renderD129

When a Docker Compose volume bind-mounts a GPU device node (e.g., /dev/dri/renderD129), if that device file does not exist on the host, Docker creates an empty regular file at that path instead of the expected character device. The container starts but immediately exits with code 255 — silently, with no useful error message — because the "device" it receives is an empty file, not a real GPU.

Key Points

  • Docker bind-mounts a non-existent device path → Docker creates an empty file, not a char device
  • Container exits with code 255 immediately on start — no diagnostic message in logs
  • GPU device node numbers depend on the host hardware: renderD128 is the first render device, renderD129 would be a second GPU that may not exist
  • Always verify available device nodes with ls -la /dev/dri/ before configuring bind mounts
  • For Jellyfin in Docker inside LXC: the correct device is almost always /dev/dri/renderD128 unless the host has multiple GPUs

Details

How the Bug Manifests

A typical Jellyfin docker-compose.yml includes GPU access for hardware transcoding:

devices:
  - /dev/dri/renderD129:/dev/dri/renderD129

If the Proxmox host only has one GPU (most homelab builds), only renderD128 exists. When Docker starts the container, it tries to bind-mount renderD129 — which doesn't exist on the host. Docker creates an empty regular file at /dev/dri/renderD129 and passes it to the container. Jellyfin attempts to open the device, gets an empty file instead of a char device with the right major:minor numbers, and the VA-API or DRI initialization fails. The container exits with code 255.

docker logs jellyfin shows nothing useful — the process exits before writing any output.

Diagnosing the Problem

# On the Proxmox host (or LXC host with GPU passthrough) — check available DRI devices
ls -la /dev/dri/
# Output:
# crw-rw---- 1 root video 226, 0 May 3 14:00 card0
# crw-rw---- 1 root render 226, 128 May 3 14:00 renderD128
# ← renderD129 does NOT appear

# Check what Docker actually passed to the container
docker inspect jellyfin | grep -A 5 "Devices"
# Look for empty file instead of char device

The Fix

# docker-compose.yml — use renderD128, not renderD129
devices:
  - /dev/dri/renderD128:/dev/dri/renderD128

Also confirm in LXC config that the GPU is properly passed through to the LXC container (not just to Docker inside it):

# /etc/pve/lxc/<CTID>.conf — required for GPU passthrough to LXC
lxc.cgroup2.devices.allow: c 226:* rwm
lxc.mount.entry: /dev/dri dev/dri none bind,optional,create=dir

renderD128 vs renderD129 Explained

GPU device nodes follow a kernel naming convention:

  • card0, card1 — primary display interfaces
  • renderD128 — first render device (DRM render node, offset 128 from base)
  • renderD129 — second render device (would require a second GPU or specific multi-head config)

For a typical homelab server with a single iGPU (Intel HD/UHD) or discrete GPU, only renderD128 exists. The 129 variant appears only with multiple GPUs or in specific VGPU setups.

Sources

  • daily/2026-05-03.md — CT111 Jellyfin down; exit code 255; root cause was /dev/dri/renderD129 not existing on host, Docker created empty file instead of char device; fixed by changing to renderD128