The device list shows the camera. The kernel driver is loaded and bound. Then the capture application refuses to open it, and the log ends in a BadParameter error from the stream consumer. This split — detected but not openable — is one of the most common commissioning failures on embedded Linux capture stacks, and it is almost never a camera fault. This guide walks the four checks in the order that finds the fault fastest: runtime directory, graphics session, release match and account context. You will finish with the camera open and a prevention set-up that keeps it open across the next boot.
Where detection stops and opening starts
Detected means enumeration succeeded: the driver bound, the device node exists, and your tool lists the camera. That proves the physical link and the driver stage. Earlier failures live before this point — a GMSL camera that never appears at all is a capture-card and cabling problem, covered in the GMSL camera not detected guide, and a USB camera that lsusb sees but the SDK does not is its own enumeration fault, covered in the USB camera not detected on Linux article.
Opened is a later handshake. The application builds a capture context, then creates its stream consumer — the client that receives frames. On GPU-composited embedded stacks, frames cross an EGL stream, and the consumer must create its endpoint before a single frame can flow. When endpoint creation fails, the open fails, and the error names the consumer side: a frame-consumer initialize call, not a sensor register. That is why reinstalling the driver targets the wrong stage. A context that crashes on creation, before any consumer exists, is a sibling failure with its own settings-and-paths fix in the 3D camera context creation crash article.
The open succeeds only when the consumer delivers its first frame. A camera that opens and then shows a flat grey picture failed after this handshake — a different stage, covered in the camera works in setup but grey image article.
Read the log lines before touching the driver
The signature below is the one to match. The first line is an environment warning printed before any camera call. The two BadParameter lines show the consumer's initialize failing and propagating out of create. The last line is the GUI reporting it has no image to draw.
QStandardPaths: XDG_RUNTIME_DIR not set, defaulting to '/tmp/runtime-root'
(Argus) Error BadParameter: (propagating from src/eglstream/FrameConsumerImpl.cpp, function initialize(), line 89)
(Argus) Error BadParameter: (propagating from src/eglstream/FrameConsumerImpl.cpp, function create(), line 44)
QPixmap::scaled: Pixmap is a null pixmap
XDG_RUNTIME_DIR is a standard Linux desktop variable. It points at a per-user, per-boot directory — normally /run/user/1000 for the first user, created at graphical login with mode 0700 — where graphics clients keep sockets and lock files. When the variable is unset, GUI frameworks fall back to a directory under /tmp named for the current user; run the same tool under sudo and the fallback becomes /tmp/runtime-root. If that directory is missing, left over from a previous boot, or owned by another account, the consumer cannot create its stream endpoint, initialize aborts with BadParameter, and the open fails.
Cause 1: the runtime directory, missing or wrong
This is the most likely cause, and two tests settle it in seconds.
- Run
echo $XDG_RUNTIME_DIR. Empty means the session never set it — normal over SSH, in services and cron, and always under bare sudo. - Run
ls -ld /tmp/runtime-* /run/user/$(id -u). The correct directory is owned by the user running the capture tool, with mode drwx------ (0700). A stale /tmp/runtime-root owned by root is the classic find.
At the bench, the fix is to log in at the device's own desktop: the session manager creates /run/user/1000 with 0700 automatically, and the tool opens. Over SSH or in a service, define the variable to a private directory you own:
export XDG_RUNTIME_DIR=$HOME/.cache/runtime
mkdir -p $XDG_RUNTIME_DIR
chmod 700 $XDG_RUNTIME_DIR
No reboot, no reinstall. Rerun the tool as the same user and the open should succeed.
Cause 2: no local graphics session
The consumer builds its stream endpoint through the board's GPU and display stack. In a bare SSH session, and in some remote-desktop setups, that stack is not attached to your login. Endpoint creation fails, and you see the identical BadParameter lines with every environment variable already correct.
Test it in one minute: run the exact same command at the device's own keyboard and screen, then over SSH. Works at the console, fails remotely — session cause. Two quick checks support it: echo $DISPLAY and echo $WAYLAND_DISPLAY are both empty in a bare SSH session, and loginctl list-sessions shows whether your user holds a local seat (seat0).
Fix: commission at the console. For unattended operation, run acquisition from a service with its own environment, and keep operator tools on a local session. The same detected-but-will-not-open split exists on desktop stacks: the GigE Vision camera that OpenCV cannot open fails the same handshake for its own reasons, and the first GenTL read that always fails is its GenTL cousin.
Cause 3: framework and driver from different releases
After an OS update or a partial SDK install, the capture utility is built against one release of the board's multimedia API while the camera stack on the system is another. The consumer's initialize then rejects the stream setup with the same BadParameter text, on hardware that worked the day before.
Test: print both versions. The capture tool has a version flag, and the camera stack prints its release when its service starts. If the camera stack was updated and the tools were not rebuilt, the numbers differ.
Fix: install the camera stack and the capture tools from the same release — a matched pair, not just the driver again. Rebuild sample or in-house tools against the installed headers. This is the one case in this guide where reinstalling is the right move, and the pairing rule is the same one behind the camera firmware version mismatch fix and the 3D camera header and SDK alignment guide.
Match your fingerprint to the fix
| Log fingerprint | Failing stage | Confirmation test | Fix |
|---|---|---|---|
| XDG_RUNTIME_DIR warning, then BadParameter at initialize | Consumer endpoint creation |
echo $XDG_RUNTIME_DIR prints nothing |
Set a user-owned 0700 directory; drop sudo |
| BadParameter only over SSH or remote desktop | Graphics session | Works at the bench console | Run capture in the local session |
| BadParameter after an OS or SDK update | Release mismatch | Tool and stack versions differ | Install driver and tools from one release |
| Fails only when launched from a service or cron | Session plus runtime dir | Print the variables inside that context | Create a 0700 dir owned by the service account; set the variable in the unit |
Read the rows top to bottom: that is also the order of probability on the bench.
Worked example: from BadParameter to first frame
Run these as the login user, in order. The whole sequence takes under ten minutes.
- Reproduce with the diagnostic tool that dumps the kernel log, and confirm the three-line signature above. It prints within a second or two of the failed open.
-
echo $XDG_RUNTIME_DIRprints nothing. Environment fault confirmed. - Find your account's standard runtime path:
id -ureturns 1000 for the first user on most distributions, so the session path is /run/user/1000. - Check it with
ls -ld /run/user/1000. It should show drwx------ with your account as owner. The mode decodes as owner read+write+execute, 4+2+1 = 7, group none = 0, other none = 0, giving 0700. The directory itself is empty except for the session's sockets, and sits on a tmpfs sized in the low tens of MB. If it does not exist because you are in an SSH session, create your own with the three commands in Cause 1. - Export the variable and rerun the capture tool as the same user. The BadParameter lines are gone and the first frame arrives.
- If step 5 still fails, move to the session check — console versus SSH — then the version check, in that order.
Decision: on this signature, fix the environment first. In the traced cases the camera opened on the first rerun after the variable was set — no driver reinstall and no reboot.
When the usual answer is wrong
- Reinstalling the camera driver. Detection already proved the driver; the failure is downstream. Skip it unless the versions differ.
- chmod 777 on the runtime directory. It breaks the per-user isolation the stack expects and leaves the unit less secure. Use 0700 with the right owner.
- Rebooting. It clears a stale /tmp/runtime-* until the next mismatch, and the unset variable returns with the next service or SSH run.
- Replacing the camera. Run the swap test: a second camera on the same host shows the same error. The host is the patient. Stage-by-stage isolation is the same discipline as the USB camera preview that freezes mid-run.
Prevention for production units
- Set the environment in the service unit, not in a login shell: XDG_RUNTIME_DIR pointed at a dedicated directory owned by the service account, mode 0700, created at boot.
- Pin the camera stack and the capture tools to one release and update them as a pair.
- Never run acquisition under sudo or a shared root shell; grant device access with groups.
- Archive the working environment: run printenv next to the commissioned setup and keep the output with the project files, so the next engineer reproduces it exactly.
- Add a two-line self-test at startup — open the camera, request one frame, log the result. It turns a silent line-down into a timestamped log entry.
If you are still choosing the stack
This failure class lives in capture paths where frames cross a GPU-composited EGL stream tied to a desktop session. Standard machine-vision interfaces avoid the dependency: GigE Vision and USB3 Vision cameras enumerate and open through the GenICam producer with no display stack involved, so the open handshake survives headless service operation.
For the host, the MV-VC5525-256G70-NN pairs PoE camera ports with light outputs on 8 built-in channels, so camera links and lighting run from one controller.
- LAN ports
- 5+ LAN ports
- USB 3 ports
- 3-4 USB 3 ports
- PoE
- PoE camera ports
- Light outputs
- 8 built-in channels
On the camera side, the MV-CU020-90GC is a 2.5 MP GigE camera with a global shutter, a 1/1.7" sensor and a C-mount. The LS-CMR-0166 carries 12 MP on USB3 and runs 30 fps at 4000 × 3000.
- Sensor format
- 1/1.7"
- Lens mount
- C-mount
- Sensor format
- 1/1.7"
- Interface
- USB3
Both open over their own standard protocols, which is what removes the desktop dependency that produced the BadParameter lines above. To pair a camera and host with the right lens and lighting, start at the camera configurator or browse the area scan cameras and vision controllers categories. If the signature resists after these checks, send us the full log through the contact page and we will read the stages with you. More stage-by-stage capture fixes sit on the systems topic page.
Questions
Why does the camera open with sudo but fail as the normal user?
Because sudo changes the runtime directory. XDG_RUNTIME_DIR is dropped, the tools fall back to a root-owned directory under /tmp, and the stream consumer cannot see the endpoints created in your own directory. Run capture tools as the login user and grant device access with group membership instead. If a service must run as root, create a 0700 directory owned by that account and point XDG_RUNTIME_DIR at it in the service unit before the capture stack starts.
Is a BadParameter error from the frame consumer a camera fault?
No. The error text names the consumer side of the pipeline, not the sensor or its driver. Detection has already proven the driver bound and the device enumerated; the open fails when the application's stream consumer initializes its endpoint. Swap in a different camera on the same host and the same error appears, which convicts the host environment. Work through the runtime directory, session and version checks before suspecting hardware.
Can I open an EGL-stream camera over SSH or remote desktop?
The consumer needs the board's local graphics stack to create its stream endpoint, so an open that works at the bench console fails in a remote session with identical BadParameter lines. Commission at the device's own desktop. For unattended operation, run acquisition from a service with its own environment, or move the camera to a GigE Vision or USB3 Vision link whose open handshake does not depend on a display stack.
What permissions should the runtime directory have?
Mode 0700, owned by the account running the capture application. The standard location is /run/user/UID, created at graphical login; list it with ls -ld. A directory open to group or other defeats the isolation the stack expects, and one left behind by a different user fails outright. Recreate it rather than loosening the mode: mkdir, chown, then chmod 700.
Do I need to reinstall the camera driver?
No. Detection already proves the driver and the enumeration work; the failure sits downstream at the consumer. Reinstalling changes nothing on that side and costs the time you would spend on the real fix. Reinstall with a purpose only when the camera stack and the capture tools carry different release numbers after an update, and then install the matched pair together.


