Every frame a depth camera delivers opens with a header, and the capture library checks a constant in that header before it reads the bytes behind it. When the check fails you get the warning that names this fault: bad magic number 0x0, repeated per subdevice, until a timeout ends the capture. The camera itself is usually healthy — it enumerates, a clip plays in a desktop player, the cable checks out. What is broken is the hand-off between the kernel driver and the library, and on a Linux depth camera that hand-off fails in five familiar ways. They are ranked below from most to least likely, each with a test, a fix and the decision that ends the search.
What the warning actually tells you
A magic number is a constant written into a file or frame header so the reader can confirm the layout before parsing. Depth payloads on a UVC camera carry such headers, and the library validates the value before interpreting what follows as depth data. The message therefore reports a software layout failure, not a hardware fault.
The two signatures differ in one useful way. A constant 0x0 means the header position held zeros: the driver handed over a buffer it never filled. A value that changes every run — garbage that looks like pixel data — means payload bytes are present but shifted, so the parser reads data where the header should be. Both point at the same place: the code that fills and frames those buffers, which is the kernel's video driver, not the camera's optics.
Expect companions in the same log: frame-status warnings, then a timeout when the library gives up, and pipe errors (LIBUSB_ERROR_PIPE) when a stream refuses to start at all. Treat every one of these as a driver-stack symptom until the procedure below proves otherwise.
Why a clip in a desktop player is not a test
A player opens the camera with its default: one stream, a standard compressed format, a size the stock driver handles. The test passes and proves power, cable and enumeration.
The capture SDK asks for far more: depth, color and one or two infrared streams running together, in uncompressed formats with device-specific payload headers. Every one of those requests must survive the same kernel module. Payload-header handling in the mainline UVC driver has been reworked since it was first written, with validation fixes landing in later kernels; the kernel tracker and driver changelogs document that history if you need the specifics. A module that plays any clip perfectly can still be the wrong build for a depth camera.
So strike the player from the evidence. The only valid test is the SDK itself, one stream at a time.
The causes, most likely first
1. The loaded module is not the build you patched
The kernel runs exactly one UVC driver: a module file chosen through depmod's index, or a driver compiled into the kernel image. Three things silently leave the stock build running: the patched file lands in a directory the index does not cover, depmod never runs after the copy, or the module is not reloaded after the file changes. The stock build decodes standard formats and passes custom depth payloads through untouched — the header check fails on exactly those streams.
Test: run modinfo uvcvideo and read the filename and version; run uname -r. The filename must sit under /usr/lib/modules/$(uname -r)/, and the version must match your patched build. The version the running kernel actually holds is in the module's sysfs entry, /sys/module/uvcvideo/version.
Fix: install the patched module into the running kernel's updates directory, run depmod, reload the module or reboot, and re-run modinfo until the filename and version change. A driver built into the kernel blocks the file swap entirely — see the built-in driver check. If the patch never applied cleanly, work through the source-tree mismatch fix and the missing-file diagnosis.
Decision: color decodes while depth and infrared corrupt is this cause's signature. Clear it before testing anything else.
2. The kernel series sits outside the SDK's support
A driver patch hard-codes where payload handling lives in the kernel source. Kernels a few series later move that code, so an old patch refuses to apply, or applies and changes nothing. Newer is not better here: what matters is the series the SDK documents.
Test: compare uname -r against the kernel support in the SDK release notes. After patching, search the source tree for .rej files — rejected chunks mean the patch did not land.
Fix: move the machine to the documented series, normally a long-term-support kernel. If the patch will not apply, weigh the options in the patch-failure decision guide; if a rebuild left the system worse off, follow the rollback procedure.
Decision: pin the kernel version in production. SDK support, not recency, is the requirement.
3. The streams together exceed the port's budget
The host controller reserves isochronous bandwidth when each stream starts. Depth, color and infrared combined can pass one controller's budget even when every stream fits alone. The start call then fails with a pipe error, or frames arrive truncated and fail the header check. Scheduling shifts between runs, so errors that move to a different subdevice each run are the tell.
Test: bring the streams up one at a time, in the order given below, and note the step where corruption begins.
Fix: use a root port on its own controller, drop any hub, and lower frame rate or resolution until the total fits — the arithmetic is two sections down. The USB bandwidth check covers the same limit from the timeout side. On Windows the same failure shows as a media-type error instead: see the Windows stream-setup fix.
Decision: streams alone clean, streams together broken — bandwidth, not the driver build.
4. Autosuspend and resume corrupt the pipe
The kernel's camera documentation is explicit that the whole pipeline must stop streaming at suspend and restart cleanly at resume — the camera-sensor pages in the kernel's driver API docs carry that requirement. A multi-stream UVC device that resumes half-initialized delivers payloads the header check rejects. Desktop autosuspend reproduces the same effect after a few idle minutes, no suspend required.
Test: run clean for a minute, suspend and resume, run again. Then reproduce after leaving the stream idle long enough for autosuspend to fire.
Fix: disable autosuspend for the camera — set its power/control attribute to on — and restart the capture application after every resume.
Decision: warnings that begin only after a resume or an idle gap point at power management, not at the module build.
5. Cable, hub or controller hardware
Least likely, but real: truncated isochronous packets fail the header check exactly like software faults, and the physical path can produce them.
Test: swap the cable, then plug the camera directly into a root port, then try a different controller if one is available.
Decision: warnings persisting with a verified module build, a single stream and no hub justify this hardware round. If two machines with verified builds fail identically, the camera goes back for service — contact us and we will take it from there.
The bring-up order that separates the causes
- Power-cycle and replug the camera. A pipe error at stream start sometimes clears with fresh enumeration; a persistent one is evidence.
- Run the module checks from cause 1:
modinfo uvcvideofilename and version, the sysfs version, anduname -r. Write all three down. - Start the depth stream alone and run it for 60 seconds. Record warnings by subdevice index.
- Add color and repeat.
- Add each infrared stream one at a time, repeating the 60-second run.
- Suspend and resume once, then run again.
- Match the pattern against the table.
- Apply the one matched fix and repeat the same order.
| What you see | Points at | Fix |
|---|---|---|
Color decodes, depth and infrared warn; modinfo shows the old filename or version |
Cause 1 | Install into updates/, run depmod, reload |
Warnings on every stream; .rej files in the source tree |
Cause 2 | Move to the SDK's kernel series, usually long-term support |
| Each stream alone runs; the third one warns or times out | Cause 3 | USB 3 root port, lower frame rate, no hub |
| Clean run turns corrupt after suspend, resume or idle | Cause 4 | Autosuspend off; restart capture after resume |
| Warnings persist: verified build, one stream, no hub | Cause 5 | Swap cable, then controller |
A stream that never starts at all is a different fault from one that starts corrupt — the missing-streams diagnosis covers that signature.
The bandwidth budget, with the arithmetic
The second line is the whole USB 2.0 story: the 480 Mb/s printed on the box is a signaling rate, while isochronous data moves at most 1,023 bytes per microframe transaction, up to three transactions per microframe, 8,000 microframes per second — about 24.6 MB/s of real budget.
Worked example, with example formats (read the real ones from your SDK's stream table):
- Depth, 480 × 360 pixels at 2 bytes per pixel: 480 × 360 × 2 B = 345,600 B per frame; at 30 fps that is 345,600 × 30 = 10.4 MB/s, or 82.9 Mb/s of payload.
- Two infrared streams at the same format: 2 × 10.4 = 20.7 MB/s.
- Color, 640 × 480 at 2 bytes per pixel, 30 fps: 640 × 480 × 2 B × 30 = 18.4 MB/s.
- Total demand: 10.4 + 20.7 + 18.4 = 49.5 MB/s against a 24.6 MB/s budget — over by a factor of two, so frames truncate and the header checks fail.
Decision: move the camera to a USB 3 root port, where the budget is in the hundreds of MB/s. If USB 2.0 is unavoidable, drop to 15 fps: the three monochrome streams then total 345,600 × 15 × 3 = 15.6 MB/s and fit with about 9 MB/s of headroom for a reduced color stream (320 × 240 at 2 bytes per pixel and 15 fps adds 2.3 MB/s).
Fix the stack once, or remove the failure class
Some single-machine stacks are worth patching. A production cell that repeats this procedure at every kernel update is paying maintenance on the fault for the station's whole life, so price that honestly before you commit to it.
When you specify the next station, remove the failure class instead of managing it. A GigE Vision camera streams over Ethernet through its own libraries, so the UVC module never loads — the area scan cameras range is where those live. Integrated depth sensors take it further and compute depth in the device: laser profilers, structured-light cameras and time-of-flight cameras in the 3D sensors range hand the application finished measurements instead of raw payloads.
Laser profilers and stereo 3D cameras
170 models · from $699.00Three examples from that range:
- Type
- Laser profiler
- Type
- Stereo / structured light
- Type
- Depth / ToF camera
Keep it fixed
- Pin the kernel series on production cells and test every update on a bench machine first.
- After each update, reinstall the module into the new kernel's
updatesdirectory, rundepmod, and re-run themodinfocheck before the camera runs production again. - Record kernel version, module version and SDK build in the station file, next to the camera serial.
- Make single-stream bring-up part of acceptance for every new depth camera on Linux.
The rest of this series — driver loading, patch failures, rollback, kernel compatibility — sits on the 3D topic page. To specify hardware that skips the UVC stack entirely, start at the camera finder or run the camera configurator to match camera, lens and light in one pass.
Questions
Does a bad magic number warning mean the camera is faulty?
Almost never. The warning is a layout check failing in software: frames arrive, but the bytes behind the header are not what the library expects. Failing hardware normally shows no stream at all, identical corruption on every machine, or constant frame-status errors on every run. Capture on a second PC with a verified module build; if all streams decode cleanly there, keep the camera and keep working the driver list.
Can I run depth on one USB port and color on another to dodge the bandwidth limit?
No. The streams are interfaces of one camera; a UVC device exposes them through a single USB configuration, so you cannot split them across controllers. What you can do is lower the frame rate or resolution per stream, move the whole camera to a USB 3 root port, or use a controller with enough isochronous budget for the combined total from the worked example.
How do I check which driver build the kernel actually loaded?
modinfo uvcvideo reads the module file depmod's index resolves: check its filename sits under /usr/lib/modules/$(uname -r)/ and note the version and date. The build the running kernel holds shows in the module's sysfs version entry. If on-disk and loaded versions disagree with your patched build, install into the updates directory, run depmod again, reload the module, and confirm both values change.
Can a USB hub cause bad magic number warnings?
Yes, as the rare fifth cause. A hub shares one controller's isochronous budget between devices and adds a second cable run; either can truncate packets, and a truncated frame fails the header check exactly like a driver mismatch. Plug the camera straight into a root port on its own controller and rerun the single-stream test. If warnings persist with a verified module and one stream, the hub was innocent — move on to the controller.
Should I install the newest kernel so no patch is needed?
No. The patch exists because the driver needs behavior the stock build lacks for your camera's payload formats, and a newer series does not guarantee that behavior — it usually moves the code the patch targets. Run the kernel series the SDK documents, normally long-term support, and re-check the loaded module after every update. Treating kernel recency as progress turns each camera bring-up into an experiment.


