A 3D camera that worked fine this morning suddenly refuses to open for a different Linux user. The SDK still lists the device, USB is healthy, and then initialisation stops with a message about failing to open a shared memory device lock. The camera is not broken and no other process is streaming; what is broken is a small lock file in /dev/shm that the previous user's session never cleaned up. This guide walks through the diagnosis, the safe way to clear the lock, and the habits and code changes that stop it coming back. It applies to any 3D camera or depth SDK that uses a POSIX shared memory object to enforce single ownership on one host.
Symptom: the device is found but never opens
The signature of this failure is a log that shows two things in sequence:
- Device discovery succeeds. The SDK prints the camera name, product ID, serial number and the USB connection speed, so enumeration and permissions are fine.
- Immediately after, node loading fails or blocks with an error such as a failure to open a shared memory device lock.
The key clue is that the camera appears in the device list. If USB permissions or node permissions were the problem, discovery itself would fail or return nothing, which is the territory of our Linux camera device permissions guide. Here the failure happens one step later, at the point the SDK tries to claim exclusive ownership of the camera across processes and users.
Likely causes, in order of probability
Work down this list; the first cause covers the large majority of cases.
1. A stale shared memory lock from an earlier session
Many 3D camera SDKs create a POSIX shared memory object in /dev/shm, named something like a device lock, the first time a process opens the camera. The object acts as a cross-process flag: "someone already owns this camera". The intended lifetime is short, created on open and unlinked with shm_unlink on clean exit.
The failure mode is that the second user cannot even open the object, because the first user's process created it with permissions that do not allow a different user to reopen it read-write. The classic reproduction is exactly the scenario in the field reports:
- Log in as user A over SSH and launch the camera node.
- Stop the launch file, for example with Ctrl+C, or let it crash.
- Log in as user B and launch the same node.
- Discovery succeeds, then the node fails or blocks on the shared memory lock.
Some SDK versions create the lock object but never call shm_unlink in the driver destructor, so the object survives both clean and unclean exits. Because the object was created by user A, user B's shm_open with read-write access fails on permission grounds and the SDK reports it as a failure to open the shared memory lock. On top of that, tmpfs keeps the object alive until reboot, since no process holds an open file descriptor that would clean it up on exit.
2. A live process you forgot about
Before blaming a stale lock, rule out a real owner: a camera node left running in another session, a composable node container that did not shut down, or a background service from the previous user. This looks similar but is legitimate behaviour. It also overlaps with the situation in multi-camera shutdown latency: diagnose slow pipeline stops, where containers keep processes alive after the launch command returns.
3. Container namespace confusion
If the camera is passed into a container, each container has its own /dev/shm by default. A lock created inside the container is not the same object the host sees, so ownership checks can silently pass in both places, or fail for a different reason than you expect. See camera in Docker: pass V4L2 media nodes, not just /dev/video0 for the device-side set-up, and treat lock visibility across namespaces as a separate design decision.
Test: confirm which cause you have
Run these checks as root or with sudo, on the host that runs the camera software.
- List the shared memory objects and look for lock-named files:
ls -l /dev/shm/
A file with a name containing "lock" and the camera vendor's tag, owned by the first user, is your prime suspect. Note the owner, group and permissions in the listing.
- Check whether anything still holds it or the camera:
ps aux | grep -i camera
lsof /dev/shm/<lock-file-name> 2>/dev/null
If lsof returns nothing and no camera node or container process is running, the lock is stale.
- Confirm the camera itself is free. Unplug and replug it, or check that the second user can see the USB device. If a second physical camera is involved, also read two depth cameras USB busy: fix the interface claim error to separate a kernel interface-claim error from this userland lock.
Fix: remove the stale lock
With no live process holding the camera or the lock object:
-
Stop all camera software: launch files, node containers, SDK tools, viewers.
-
Verify with
ps aux | grep -i camerathat nothing remains. Kill any survivor and wait for it to exit. -
Remove the stale object:
sudo rm /dev/shm/<lock-file-name>
Removing a file in /dev/shm is the same as calling shm_unlink on it. The tmpfs is RAM-backed, so nothing is written to disk and the object cannot be recovered, but a lock object is meant to be recreated from scratch on every open anyway.
-
Relaunch the camera node as the intended user. Discovery and open should now complete, and the SDK recreates the lock object owned by this user.
-
If a reboot is cheaper than the investigation, that also clears /dev/shm entirely, because tmpfs contents do not survive a restart. On a production line, the targeted removal above avoids stopping the whole cell.
Why the lock exists at all
The lock is not gratuitous. Two processes opening one depth camera produce interleaved control transfers and unusable point clouds, so the SDK enforces one owner per device per host. POSIX shared memory is a reasonable tool for that: it works across unrelated processes and survives fork. The formula of the pattern is simple:
The bug in affected SDK versions is that the second line never runs: the file descriptor is created at driver construction, but the destructor path does not unlink the object, so every exit, graceful or not, leaves it behind. Combined with per-user creation permissions, the next user cannot open it. That is why the error follows the second user rather than the first, and why the same user relaunching usually works.
Prevention: keep one owner and clean up
-
One user, one camera. In a shared workstation or robot cell, pick a single service account that owns the camera process. Interactive users talk to that service, not to the device. This removes the cross-user permission problem entirely.
-
Shut down through the SDK. Stop launch files with their own shutdown path so destructors run. Avoid
kill -9on camera processes; it guarantees no unlink happens. -
Add a pre-start cleanup. In a systemd unit, an ExecStartPre line that removes the lock object when no camera process is running makes the failure self-healing:
ExecStartPre=/bin/sh -c 'pgrep -f camera_node || rm -f /dev/shm/<lock-file-name>'
-
Handle signals. If you wrap the SDK, install handlers for SIGINT and SIGTERM that run the normal teardown, so Ctrl+C unlinks the lock instead of abandoning it.
-
Watch for it in CI. Multi-user and multi-session tests are where this surfaces first; our multiple USB depth cameras on Linux: startup troubleshooting guide covers the wider start-up checks to run alongside.
-
Keep firmware and SDK aligned. Lock-handling bugs are version-specific, and a mismatched pair produces its own detection failures, as covered in camera firmware version mismatch: fix detection failures safely. Update the SDK from the manufacturer's official release channel so the fix, once shipped, reaches your system.
Choosing parts for a single-owner 3D station
If you are rebuilding the station anyway, choose the camera for the measurement task first and keep the host architecture simple: one camera, one service account, one process tree. A time-of-flight camera suits volumetric and presence tasks, while a laser-galvanometer stereo camera suits structured-light scanning of static parts.
- Type
- Depth / ToF camera
- Type
- Stereo / structured light
Both are in our 3D sensors range, alongside laser profilers for continuous profile measurement. For 2D inspection alongside the depth stream, the area scan cameras finder filters by interface and mount, and the camera configurator walks the full chain from sensor to host. If you are unsure which sensing technology fits your part geometry, contact us with the part dimensions and tolerances and we will narrow it down.
Checklist before you call it fixed
- Discovery lists the camera and open completes for the intended user.
-
ls -l /dev/shm/shows the lock object owned by the current user, or absent when no camera software runs. - A graceful stop leaves no lock object behind; if it does, the SDK version still lacks the unlink and the pre-start cleanup must stay.
- A forced stop followed by a relaunch recovers without manual intervention.
- Only one service account opens the camera; interactive users go through its interface.
- The fix is recorded in your deployment notes, so the next engineer does not reboot a cell over one tmpfs file.
Stale shared memory locks are annoying precisely because the camera looks perfectly healthy right up to the open call. Ninety seconds with ls, ps and rm clears it; a single-owner service design makes sure you never spend those ninety seconds again.
Questions
Is it safe to delete files under /dev/shm?
Only after you have confirmed no running process still needs them. POSIX shared memory objects in /dev/shm are just RAM-backed files, and the kernel recreates them on demand. First check with ps or lsof that no camera node or SDK process is alive; if one is, close it gracefully. If nothing holds the object, unlinking it is safe and it disappears anyway on the next reboot, because /dev/shm is a tmpfs.
Why does the error mention shared memory when the camera is on USB?
The USB link is fine; that is why the device still enumerates in the SDK's device list. The shared memory object is an inter-process lock the SDK creates so that two applications on the same host do not grab one camera at the same time. The failure happens at the locking step, after discovery, so the camera is found but never opened. It is a host-side ownership problem, not a camera or cable problem.
Will rebooting fix it?
Yes, almost always. /dev/shm is a tmpfs, so its contents vanish with the power. A reboot is the blunt fix when you cannot identify which process owns the lock. For a production line you usually want the faster path: stop the camera software cleanly, verify no process is left, unlink the stale object, and restart, which avoids bringing the whole cell down for one lock file.
Does this happen with Docker containers too?
It can, and it is more confusing there. Each container has its own /dev/shm namespace by default, so the lock the container creates is not the same object the host or another container sees. If you share the camera device with a container, make sure the lock semantics you rely on actually span the namespaces involved, or run one owner per camera. Our article on passing media nodes into containers covers the device side of that set-up.
How do I make the cleanup automatic?
Add a small pre-start step to your service or launch file: check whether the lock object exists, and if no camera process is running, unlink it before the SDK initialises. In systemd, use ExecStartPre with a shell one-liner. Alternatively install a signal handler that calls the SDK cleanup path on SIGINT and SIGTERM, so Ctrl+C leaves no lock behind. Both together cover expected exits and crashes.

