3D visionTroubleshooting

Depth camera no GPU detected in Docker: make CUDA visible

Your depth camera reports no GPU detected because CUDA never reaches the Docker container. Run nvidia-smi twice, fix the toolkit wiring or the image tag.

LumaSpec Vision10 min read Share on LinkedIn

On this page 9 sections
  1. 01What does a no GPU detected error on a depth camera mean?
  2. 02Which two commands split the fault in half?
  3. 03What must the host prove before you blame the container?
  4. 04Why does nvidia-smi fail inside the container?
  5. 05Why does nvidia-smi pass yet the SDK still reports no GPU?
  6. 06How do you inspect a container that is already running?
  7. 07When should you skip Docker and run the depth SDK directly on the host?
  8. 08How do you keep the GPU fix from regressing after an update?
  9. 09Questions

The wrapper compiled, the container started, and the depth node still died on the same line: Error opening camera: NO GPU DETECTED. Nothing is wrong with your camera. The CUDA runtime inside the container enumerated zero devices, so the GPU never reached the container, or the CUDA generation in the image is newer than the host driver allows. This guide gives you the two-command test that bins the fault, the four-step toolkit fix, the version rule with real driver numbers, and the checks that keep it fixed through updates.

What does a no GPU detected error on a depth camera mean?

The message means the depth SDK's CUDA runtime enumerated zero usable GPU devices inside the container and gave up at camera open, before it touched the sensor. The camera, its cable and your launch file are usually innocent.

Stereo matching, structured-light decoding and point-cloud generation all run on the GPU through CUDA. At open, before any USB or GigE traffic starts, the SDK asks CUDA how many devices it can see, and zero ends the launch there. Wrapper logs usually record it as GPU ID -1. The wording differs between SDKs — "NO GPU DETECTED", "no CUDA-capable device found", "CUDA not available" — but the mechanism behind every variant is the same enumeration step.

That places the fault in the layers above the sensor, not in optics or cabling. Any GPU-accelerated stereo or structured-light 3D camera behaves identically here; the sensor never gets the chance to be the fault. For the general stack behind that startup sequence, see the 3D camera context creation crash fix.

3D sensorsHikrobot MV-DPS200P-02 Projected structured-light 3D cameraMV-DPS200P-02
Type
Stereo / structured light
$8,829.00 · quotedView and quote

Which two commands split the fault in half?

Run nvidia-smi on the host, then run it again inside the container. Two commands, about a minute, and the outcome places the fault in one of three bins — host driver, runtime wiring, or CUDA version mismatch.

On the host:

nvidia-smi

Then in a fresh container from your own image, or against the one that is already up:

docker run --rm --gpus all <your-depth-image> nvidia-smi
docker exec <container-name> nvidia-smi
Result The fault sits in The fix lives in
Host fails GPU driver on the host the host OS: install the GPU vendor driver, reboot, retest
Host passes, container fails runtime wiring the container toolkit and the Docker flags, next section
Both pass version or capability match the image tag and the CUDA env vars, two sections down

What must the host prove before you blame the container?

The host must run nvidia-smi on its own, printing a driver version and a CUDA Version line such as 12.2. That printed number is the ceiling every container image tag must stay under.

Look at the top of the nvidia-smi output: the driver version sits on the left, and the CUDA Version on the right is the maximum CUDA generation this driver can serve. The kernel module and the user-space driver libraries live only on the host; the container toolkit injects the matching user-space libraries into a container at start, which is why one host driver serves every container you run.

works: image CUDA tag <= nvidia-smi CUDA Version broken: image CUDA tag > nvidia-smi CUDA Version

The GPU vendor's CUDA compatibility table pairs driver series with ceilings, and nvidia-smi always prints the ceiling, so you never have to remember it:

Host driver series nvidia-smi prints Image tags that run
535 CUDA Version: 12.2 up to CUDA 12.2
550 CUDA Version: 12.4 up to CUDA 12.4
570 CUDA Version: 12.8 up to CUDA 12.8

Why does nvidia-smi fail inside the container?

When the host passes and the container fails, the container toolkit is missing or not wired into Docker. The fix is the same four moves: install the toolkit, register the runtime, restart Docker, recreate the container with --gpus all.

  1. On the host, install the container toolkit from the GPU vendor's package repository; the package is nvidia-container-toolkit on Debian-based hosts.
  2. Register the runtime: sudo nvidia-ctk runtime configure --runtime=docker writes the nvidia runtime into Docker's daemon.json.
  3. Restart the daemon: sudo systemctl restart docker.
  4. Recreate the container with --gpus all on Docker 19.03 and later, or with --runtime nvidia and NVIDIA_VISIBLE_DEVICES=all on older engines.
  5. Prove it with the fresh-container one-liner from the last section; nvidia-smi should now print the same driver and CUDA Version lines inside the container as on the host.

Compose files carry the same request in the deploy block, which keeps the device attached across recreations:

deploy:
  resources:
    reservations:
      devices:
        - driver: nvidia
          count: all
          capabilities: [gpu]

Once the runtime is registered, the same injection layer carries GPU access to rendering paths too — the ROS 2 point cloud passthrough fix rides on exactly this mechanism. If startup still fails after nvidia-smi passes inside the container, work through the 3D camera control software in Docker startup checklist before touching any SDK setting.

Why does nvidia-smi pass yet the SDK still reports no GPU?

A working nvidia-smi proves the driver library is injected but not that compute libraries are, and not that the image's CUDA generation matches the SDK. Two checks remain: the CUDA driver-capabilities variable and the image tag versus the wrapper's build.

Capability check. nvidia-smi needs only the utility libraries; CUDA also needs the compute libraries, and minimal images often start without them. Run docker exec <container-name> env | grep NVIDIA_ — an empty NVIDIA_DRIVER_CAPABILITIES, or a value of utility alone, explains an SDK that cannot open a device while the diagnostics look healthy. Recreate with -e NVIDIA_DRIVER_CAPABILITIES=compute,utility, adding graphics when the stack also renders a window.

Generation check. Build and run in the same CUDA generation: a wrapper compiled in a CUDA 12 image will not run under a CUDA 11 image, and the failure lands at library load or at device enumeration. Pin one tag for both stages — the same one-version rule that settles SDK version mismatches in Docker builds.

When CUDA passes inside the container and the node still refuses to start, the suspect moves to the GPU runtime stack under the node itself; the stereo depth node startup and GPU runtime libraries fix picks up from there.

How do you inspect a container that is already running?

docker exec and docker inspect answer from inside a live container without restarting it. Exec nvidia-smi shows what CUDA the container sees, and inspect shows whether the GPU was attached at creation at all.

docker exec <container-name> nvidia-smi
docker exec <container-name> env | grep NVIDIA_
docker inspect <container-name> | grep -A 2 -E '"Runtime"|"DeviceRequests"'

Read the output this way:

  • nvidia-smi prints the driver and CUDA Version table: injection works. Command not found: nothing was injected.
  • NVIDIA_VISIBLE_DEVICES reads all or a GPU index: healthy. void or empty: every GPU is hidden from this container.
  • Runtime shows nvidia: this container was started with --runtime nvidia.
  • DeviceRequests lists a GPU entry: the --gpus all flag landed. null or an empty list: the flag never made it onto this run, the usual story after editing a compose file without recreating.

Any wrong value sends you back to recreation with the right flag; every value healthy sends you to the capability and generation checks of the previous section.

When should you skip Docker and run the depth SDK directly on the host?

If nothing in your deployment needs image isolation, install the SDK and driver on the host directly and the whole injection layer disappears. We reach for bare metal when a station ships on one dedicated controller with one depth camera.

Bare metal removes the runtime wiring, the capability variables and the ceiling check: one driver, one CUDA install, and the SDK sees the GPU directly. Keep Docker when you need one image replicated across many stations or clean teardown between jobs; go bare metal for a single-box station, for display-hungry viewers, and whenever the debugging on this page costs more than the isolation buys you.

On the host side, the vision controllers line takes the GPU as a card: both units below expose PCIe expansion, and their built-in PoE camera ports feed GigE depth cameras without an added switch. Where captures accumulate, the MV-VC4712-256G10-2TH carries a 2 TB HDD next to 16 GB of RAM. Where inference shares the box, the MV-VC5525-256G70-NN pairs 32 GB of memory with 5+ LAN ports.

Specification MV-VC5525-256G70-NN MV-VC4712-256G10-2TH
CPU Intel® Core i5-12400 Intel® Core Ultra 7 processor 255H
Memory 32 GB 2 × DDR5 6400 MHz non-ECC SO-DIMM memory slots; Up to 48 GB per slot, Up to 96 GB with two slots
Storage 256 GB SSD 1 × 7-pin SATA3.0, 1 × M.2 SATA 2280, 1 × M.2 NVMe 2280; 1 × 2.5"/3.5" drive bay
GPU Intel® UHD Graphics 730 Intel® Arc 140T GPU
Operating system Unactivated Windows 10 Windows 11 64-bit (not activated)
Video output HDMI interface × 1, VGA interface × 1; Supports independent display output at the same time; Max. resolution 1920 × 1080 @ 60 Hz Independent dual display supported; 1× HDMI port, Up to 1920 × 1080 @ 60 Hz; 1× VGA port, Up to 1920 × 1080 @ 60 Hz
Digital I/O Opto-isolated input × 8; Opto-isolated output × 12 ( supports NPN/PNP switching), digital-isolated low-side driver output × 8; Non-isolated bi-directional differential I/O × 4 18 digital isolated inputs supported; 18 isolated digital outputs
Network interface GigE interface × 7, including interface for PoE × 4 4× Gigabit Ethernet ports; PoE power supported, 15 W per port, 25 W total across 4 ports
USB Interface USB 2.0 × 4, USB 3.0 × 4, built-in USB 2.0 × 1 4× USB 2.0 ports; 2× USB 3.0 ports; 1 × internal USB2.0 port
Serial Port RS-232 × 2 by default, supports switching to RS-485 and RS-422 2 × configurable RS-232/RS-422/RS-485
Light interface 24 VDC constant voltage × 8; (Max. power consumption of single channel is 72 W, total max. power consumption 190 W) SMR-03V-BC female; 6-channel 24 V constant-voltage light drive, Max. power per channel: 72 W, Max. total power: 110 W
Extended interface SATA 3.0 interface × 2, M.2 NVME interface × 1; PCIe × 16 extended interface × 1, PCIe × 8 extended interface × 1, PCIe × 4 extended interface × 2; (When the PCIe × 8 extended interface is used, the PCIe × 16 will only provide half of the bandwidth.) 1× PCIe 4.0 x8 slot, 2× PCIe 4.0 x4 slot
Price $4,479.00 · quoted $6,049.00 · quoted

All 2 share: Certification CE, KC. Values as printed in each product's data sheet; open a part for its drawing and full specifications.

One warning travels with either setup: a viewer that opens a window needs a display stack, and inside a container that is an X11 and OpenGL question, not a GPU one — the camera preview display-variable fix covers it.

How do you keep the GPU fix from regressing after an update?

Pin three values in writing — the image tag, the host driver series and the --gpus flag in the compose file — and make the container fail fast with a clear line when nvidia-smi reports nothing.

  • Pin the CUDA image tag; never let it float to latest, because a major generation jump breaks the ceiling rule silently.
  • Write the driver series and its printed CUDA Version into the station sheet, and rerun nvidia-smi on the host after every driver or kernel update.
  • Keep the GPU reservation inside the compose file so a recreated container keeps its device.
  • Fail fast in the entrypoint: run nvidia-smi -L at start and exit with a line that names the empty result, so the next person sees the cause instead of a stack trace.

Once nvidia-smi prints inside the container, rerun the depth node; most stacks open on the first attempt after the ceiling check passes. If you are sizing a new depth station instead of repairing one, start at the 3D sensors category or its camera finder, start the system configurator at the camera step, or send us both nvidia-smi outputs through the contact page and we will check the driver and image pairing. The surrounding Docker, trigger and point-cloud guides sit on the 3D vision topic page.

Questions

Does the depth camera itself ever cause a no GPU detected error?

No. The SDK counts CUDA devices before it opens the sensor, so a camera fault shows up later as a device-not-found or timeout message instead. One nuance: some SDK builds fall back to CPU processing and only log the missing-GPU line, so if frames do appear, check the node's processing device setting, because CPU fallback runs stereo at a fraction of the GPU frame rate.

Can I attach a GPU to a container that is already running?

No. Docker fixes a container's devices at creation, and docker update only changes CPU and memory values. Recreate the container with --gpus all, or add the GPU reservation block to the compose file and bring it up again; restarting the old container will never gain the device.

Is it safe to upgrade the host driver without rebuilding the images?

Yes, and it is the safe direction: a newer driver only raises the printed CUDA Version ceiling, so older image tags keep working untouched. Restart the containers after the upgrade so the toolkit re-injects the new user-space libraries, then run nvidia-smi inside one container to confirm. The reverse, raising an image's CUDA tag under an old driver, is the move that breaks.

Do I need to install the GPU driver inside the container?

Never. The kernel module lives on the host alone; the container toolkit injects the matching user-space libraries at startup. Installing driver packages inside a container conflicts with the injected libraries and burns build time on a kernel module that cannot load in a container anyway.

Which Docker flag do I use on engines older than 19.03?

Use --runtime nvidia instead of --gpus all, and set NVIDIA_VISIBLE_DEVICES=all so the nvidia runtime exposes every GPU. Register the nvidia runtime first with the container toolkit's configure command, restart Docker, then create the container. From 19.03 onward, --gpus all does the same job without the runtime switch.