---
title: "Docker LXC GPU Device Node Mismatch — renderD128 vs renderD129"
aliases: [docker-gpu-device-node, lxc-gpu-passthrough-mismatch, renderd-mismatch]
tags: [docker, lxc, proxmox, gpu, jellyfin, homelab, hardware, debugging]
sources:
  - "daily/2026-05-03.md"
created: 2026-05-03
updated: 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:

```yaml
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

```bash
# 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

```yaml
# 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):

```bash
# /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.

## Related Concepts

- [[wiki/concepts/proxmox-lxc-autostart]] — LXC container configuration and device passthrough
- [[wiki/homelab/_index]] — homelab GPU and LXC infrastructure context
- [[wiki/concepts/docker-compose-restart-no-code-reload]] — other Docker silent failure patterns where the container appears fine but behaves wrong

## 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`
