You add a CTI file, call update(), and device_info_list comes back empty while another producer on the same machine lists every camera on the network. That pattern lands on anyone who wires GenICam acquisition into their own code through harvesters or a similar library, and it looks like a broken network when it almost never is. The list is empty because a GenTL producer only enumerates the devices its transport stack was built for, not everything on the wire. Here you will separate a coverage mismatch from a network fault with a two-line count test, work the case of a maker-specific GigE CTI that returns zero devices, and leave with a rule for pairing each camera fleet with the right producer.
What an empty device_info_list actually tells you
update() did its job. It loaded every CTI you added, ran each producer's discovery, and collected the answers. An empty list is an answer, not a crash: no added producer recognized any device it looked at. The list is the union of all producers' results, and each entry records the producer that reported it, so a non-empty list also shows you which pairing works.
If another tool on the same host already lists the cameras, the NICs, the subnet, the cabling and the cameras are all healthy. One variable remains: which producer is doing the looking. That is the same shape as camera detected but not in the acquisition tool: fix the adapter layer — the device exists, and the layer between your code and the device is the suspect. Until a test proves otherwise, treat an empty device_info_list as a coverage question about the CTI, not a network question about the plant.
The producer, not the network, decides what gets enumerated
GenTL is the EMVA standard that gives acquisition code one interface for enumerating, opening and streaming from cameras regardless of how they connect. A producer is an implementation of that interface, shipped as a CTI — a shared library with a manifest that tells the consumer it exists. Two kinds are in circulation, and they enumerate differently:
- Transport-standard producers speak the protocol themselves. A GigE Vision producer sends the standard discovery request on its NICs and lists every compliant device that answers; a USB3 Vision producer walks the bus and lists every USB3 Vision device it finds.
- Maker-specific producers sit on a maker's driver stack. Some list only that maker's own family; others implement the transport but still need the maker's runtime installed before they discover anything at all. Either way, the supported set is written by the producer, never by the network.
With cameras demonstrably reachable, an empty list means the second set contains none of them. That is a pairing problem, and you fix it by choosing CTIs, not by re-cabling. The table is the whole decision:
| Camera fleet | Producer to load | What it enumerates |
|---|---|---|
| GigE Vision cameras from mixed makers | Transport-standard GigE Vision producer | Every GigE Vision device its NICs can reach |
| USB3 Vision cameras | Transport-standard USB3 Vision producer | Every USB3 Vision device on the bus |
| One maker only, runtime maintained | That maker's own CTI | That maker's devices on the transports its stack supports |
| Mixed transports | One transport-standard producer per transport | The union, one entry per supporting producer |
Likely causes in order, with a test for each
Another producer on the same host already sees the cameras, so order the suspects like this:
- Coverage mismatch. The CTI's supported set — its transport, its device family — does not include your cameras. Test: add one CTI at a time and print len(device_info_list) after each update(). The count that jumps from 0 to your fleet size names the producer that covers you. For what a producer actually does during that call, diagnosing transport-layer startup failures walks through update().
- Runtime missing or half-installed. The CTI file exists, but the driver stack it wraps is absent, so discovery returns nothing. Test: run the maker's own enumeration tool. If it also comes up empty, install or repair that runtime before touching your code.
- The CTI never loaded. A wrong path, bad escaping in the path string, or a missing dependency can drop your only producer from the run without a loud error. Test: confirm which files the consumer accepted and which producers it reports. CTI file path errors: check Python escaping covers the path traps, and GenTL producer not listed: check Windows DLL paths covers the dependency side.
- Producer-specific discovery needs. A producer can require a particular NIC, elevated rights for raw discovery traffic, or a network a virtualized guest cannot see. Test: load the same CTI in the maker's own tool on the same host. If the tool sees cameras and your process does not, compare environments — paths, privileges, VMs. The WSL2 discovery case and reaching cameras on another subnet are the two traps that look exactly like a coverage fault.
If no producer you can load lists the camera, the fault sits below the producers. Start from ping works, zero cameras: GigE transport layer not loaded.
Worked case: one maker-specific GigE CTI, zero devices
Inputs. A fleet of GigE Vision cameras on one subnet; on the same host, a transport-standard GigE producer already lists every camera on the network. Under test: one maker-specific GigE CTI, added alone, followed by a single update(). Observed: len(device_info_list) prints 0. Expected: the camera count the transport-standard producer already reports.
Rule in words. A producer reports the intersection of reachable devices with its supported set. A maker-specific GigE producer supports its own family on its own stack; a fleet holding no camera of that family intersects to an empty set.
Arithmetic. Run 1: 1 CTI in, 1 discovery pass, 0 devices reported. Run 2, the same three lines with the transport-standard CTI: 1 CTI in, 1 discovery pass, every reachable camera reported — the count you already have. Between the two runs the host, NICs, subnet, cabling and cameras never changed. The only input that moved the count from 0 to the fleet size was which CTI was loaded.
from harvesters.core import Harvester
h = Harvester()
h.add_file('/opt/maker_sdk/gige_tl.cti') # run 1: the CTI under test
h.update()
print(len(h.device_info_list)) # prints 0
Swap the path for the transport-standard GigE CTI and the same lines print the fleet count.
Result and decision. An empty list with cameras demonstrably on the wire means the CTI's supported set does not contain your cameras — the pairing is wrong, not the plant. Threshold: if adding the matching producer moves the count from 0 to the fleet size, keep that pairing and retire the maker-specific CTI on this station. If the count stays at 0 under every producer you can load, stop swapping CTIs and work down the cause list above.
Pair every fleet with the right producer
- List the transports in the fleet. An Ethernet jack and an IP address point to GigE Vision; a USB3 cable points to USB3 Vision.
- Standardize on one transport-standard producer per transport. It enumerates by protocol, so it stays correct when you swap camera makers.
- Add a maker's CTI only for a fleet that is entirely that maker's, and only while you maintain that maker's runtime on the same host. When the pairing holds, the maker CTI adds what its SDK exposes beyond the standard's scope; when the runtime drifts, the same CTI can quietly stop discovering.
- Load every chosen CTI, run one update(), and open devices through the producer recorded in each entry, not by list position alone: the same camera can be reported by two producers at once.
- Re-run the count test after every SDK or consumer update. Expected value: your camera count. A drop means a producer's coverage changed, not that a camera died. GenTL producer version compatibility: missing function errors covers the version side of that drift.
- If you rely on GENICAM_GENTL_IN_PATH instead of add_file(), print the variable first. A stale directory in it can load a mismatched producer ahead of the right one; point it at the directory of the producer that matches the fleet.
Bench checks that settle producer versus network
To reproduce the fault on a bench before touching a production station, you need one camera per transport and a host whose NICs you control. A 2.5 MP GigE camera with a global shutter and a C-mount is a stand-in for any GigE Vision device on the wire.
- Sensor format
- 1/1.7"
- Lens mount
- C-mount
- Interface
- GigE
- Resolution
- Up to 3 MP
For the USB3 side of the same test, a 6 MP USB3.0 mono camera plays the matching role under the same pairing rule.
- Sensor format
- 1/1.8"
- Lens mount
- C-mount
- Interface
- USB3
- Resolution
- 6-10 MP
When the bench host will also run the station, pick a vision controller with 5+ LAN ports so each camera subnet keeps its own NIC and its own discovery pass.
- LAN ports
- 5+ LAN ports
- USB 3 ports
- 3-4 USB 3 ports
- Light outputs
- 4 built-in channels
- Memory
- 8 GB
Two outcomes end the argument. The count jumps to the fleet size under the matching producer: coverage confirmed, network healthy. The count stays at 0 under every producer: the suspect moves from the CTI list to NICs, subnets and drivers, and the cause order above flips.
Keep the pairing written down
One line per station prevents a repeat: fleet → transport → producer CTI → runtime version. Keep it beside the start-up script. New stations start on transport-standard producers, so a mixed fleet stays visible in one list without per-maker runtimes. When acquisition runs inside a VM or container, re-test the pairing on the guest, because a guest that cannot see the subnet fails exactly like a coverage mismatch. Whenever a count comes back short, run the two-line test first: it takes seconds and points at either the CTI list or the wire.
To assemble the bench, pick the camera side in the camera finder or start a build from the camera configurator; the area scan cameras category groups the fleet options. If a pairing still will not enumerate on hardware you bought from us, the contact page reaches the applications team.
Questions
Why does one camera appear twice in device_info_list?
Two producers were added and both support that camera, so each reports its own entry. Read the producer or transport-layer field on each entry before calling create(), because the two entries open the camera through different runtimes. If you only need one path, add only the producer you intend to open through, or filter the list on that field. A duplicate pair that suddenly shows one entry usually means a producer stopped supporting the device after an SDK update.
Where does a GenICam consumer look for CTI files on its own?
Through the GENICAM_GENTL_IN_PATH environment variable, a list of directories separated by semicolons on Windows and colons on Linux-like systems. The consumer probes each CTI it finds there, and a CTI early in the list claims a device before later ones. Print the variable before debugging an empty list: directories left behind by uninstalled SDKs survive upgrades and can shadow the producer you intend to use. Set it to the matching producer's directory when you are not passing explicit paths through add_file().
Can I add CTI files from different makers to one Harvester?
Yes. add_file() accepts several CTIs and one update() builds a shared list with one entry per supporting producer. Keep each maker's CTI paired with its own fleet and its own installed runtime: a maker's CTI can stop discovering cameras when its runtime is absent or half-updated. If two entries appear for one camera, open the one whose producer matches the runtime you actually maintain, and drop the other CTI from the station's start-up.
The camera appears in the maker's tool but not in harvesters - which side is wrong?
Neither, yet. The tool and your code may be loading different CTIs: the tool finds the producer shipped beside it, while your Harvester() starts empty and sees only what you add or what GENICAM_GENTL_IN_PATH provides. Point your code at the same CTI the tool uses, or at a transport-standard producer, then compare the two lists. If both come up empty, the fault sits below the producers, in the network or driver layer.
Does a transport-standard producer replace the maker's SDK entirely?
For enumeration and buffer transport, yes: a GigE Vision or USB3 Vision producer speaks the protocol itself and lists any compliant camera it can reach, whatever the maker. You still need the maker's runtime for features outside the standard's scope, such as a proprietary event or a code-generation tool tied to that SDK. Many fleets run entirely on transport-standard producers; keep the maker's CTI only where a device depends on it.


