System designTroubleshooting

Camera listed twice by two transport layers: dedupe by serial

Why one camera gets listed twice, how two transport layers double your camera list, and how to restrict discovery and dedupe by serial number.

LumaSpec Vision9 min read Share on LinkedIn

On this page 9 sections
  1. 01Why does one camera show up twice in my camera list?
  2. 02Is it safe to have two SDK generations installed side by side?
  3. 03Why does the vendor's viewer show one camera but my program shows two?
  4. 04How do I tell duplicates from two real cameras?
  5. 05How do I stop the second transport layer from discovering my camera?
  6. 06How do I deduplicate the camera list in my own code?
  7. 07Why does opening the second entry fail with an access error?
  8. 08How do I keep this from coming back on the next machine?
  9. 09Questions

A camera that appears twice in your program's discovery list is almost never two devices or a failing cable: it is two transport layers both enumerating one camera. That is the normal outcome of an older and a newer SDK generation installed on the same machine, and it arrives with an access error the moment your code opens the second entry. This guide gives you the one-run test that confirms the cause, the configuration change that removes the duplicate at the source, a dedupe pattern for your acquisition code, and the deployment habits that keep the list clean on the next machine.

Why does one camera show up twice in my camera list?

Because two transport layers both enumerate it: a discovery pass lists a camera once per transport layer that can reach it, so two installed SDK generations — each loading its own transport layer — report one physical camera as two entries.

Camera APIs in the GenTL style split discovery from ownership. The API loads one or more transport layer producers; each producer scans the domain it owns — a GigE Vision layer scans the network interfaces, a USB3 Vision layer scans the USB buses — and the API concatenates what they find. Nothing in that concatenation checks what another layer already listed, so anything both layers can reach appears twice.

entries listed = physical cameras × transport layers that can reach them duplicates = entries listed − physical cameras

Three cameras reachable through two layers list 3 × 2 = 6 entries, of which 6 − 3 = 3 are duplicates. Read it backwards and the list length becomes a diagnostic: divide the entry count by the cameras on the bench and the quotient is the number of active transport layers.

The mirror-image failure — the camera pings but the list comes back empty — is a transport layer that did not load at all; GenTL transport layer startup: diagnose discovery failures walks that chain from producer to device.

Is it safe to have two SDK generations installed side by side?

Yes — the two generations can coexist on one machine and neither install is corrupted; the operating rules are one generation per program and one open handle per camera, because a machine-vision camera grants exclusive access to the client that opens it.

Migration is exactly when both generations live on one PC: the old generation runs the production viewer while new code moves to the current one. Keep the split deliberate. Loading both APIs inside one process and pointing them at the same camera is refused — the second open loses — and if you ever remove a generation, run its own uninstaller rather than deleting transport layer files by hand. A configuration pointing at deleted files yields an empty list, not a shorter one.

Why does the vendor's viewer show one camera but my program shows two?

The viewer and your program load the API library from different directories, and the discovery configuration lives beside the library that loads it — the viewer's copy can restrict the transport layer path list while your program's copy still loads both generations.

So the viewer is not evidence about your program. Confirm which library copy your program actually loads — print the loaded module path at startup — before editing the configuration beside the wrong binary. In these SDK families the file is an XML list of transport layer paths, one path or several, and newer generations load every transport layer they find unless that list says otherwise. That default is deliberate, so mixed-interface stations enumerate in one call; it is also why the duplicate appears right after an update.

How do I tell duplicates from two real cameras?

Print two fields for every entry — the device serial number and the interface or transport layer it was found through — then compare rows: a duplicate pair shares one serial and differs in the second column, while two real cameras differ in both.

Pattern in the list What it means Fix
Same serial twice, two transport layers Two SDK generations both discovering Restrict the path list (next section)
Same serial twice, two interfaces Camera answering on two subnets One subnet per camera; key by interface ID
Different serials Two real cameras, same model Not a duplicate — select by serial

The two-interface row is a wiring duplicate: a camera cabled into two subnets answers discovery on both, and each interface reports it. Duplicate PoE camera discovery: diagnose host interfaces covers that case at the network level. Different serials is the case that looks like a duplicate and is not — two identical GigE cameras on one PC sorts them by identity, and two identical USB cameras: same name, open one by port does the same over USB.

The clean wiring removes the two-interface duplicate outright: one camera per port and one subnet per camera. A dual-port PoE NIC like the MV-GE2002P or a 4-port GigE card like the MV-GE1104 gives each camera its own port.

Frame grabbersHikrobot MV-GE2002P Dual-port PoE NIC, full height V2.0MV-GE2002P
Interface
GigE
Ports
2 ports
$249.00View part
Frame grabbersHikrobot MV-GE1104 4-port GigE frame grabberMV-GE1104
Interface
GigE
Ports
4 ports
$699.00View part

How do I stop the second transport layer from discovering my camera?

Set the transport layer path list in the discovery configuration to the current generation's layer only, restart the program, and the count drops to one entry per camera — three cameras list three entries, and the access error disappears with the duplicates.

  1. Locate the configuration beside the library copy your program loads (previous section).
  2. Reduce the transport layer path list to the current generation's path.
  3. Restart the program — the list is read once when the API initializes, not on each discovery call.
  4. Re-run discovery and check that the entry count equals the cameras on the bench.

If the count falls to zero you removed the working layer: restore the path and retry, one path at a time. GigE Vision camera not detected in software: fix the enumeration chain traces that failure from cable to transport layer.

How do I deduplicate the camera list in my own code?

Key the list by serial number, keep one entry per serial, and prefer the transport layer you standardize on — with 2 transport layers and 3 cameras, 2 × 3 = 6 entries collapse to 3 before anything is opened.

Position Serial (example) Found through Keep
0 SN-1001 legacy GigE layer no
1 SN-1001 current GigE layer yes
2 SN-1002 legacy GigE layer no
3 SN-1002 current GigE layer yes
4 SN-1003 legacy GigE layer no
5 SN-1003 current GigE layer yes

The kept entry is not always the first of its serial: the legacy layer may load first and own position 0, which is exactly why list position must never be the key.

# Example code: names are ours; call your SDK's real discovery API.
preferred = "current-gige-layer"                   # transport layer you standardize on
rank = {"current-gige-layer": 0, "legacy-gige-layer": 1}
by_serial = {}                                     # serial -> entry
for entry in camera_list:                          # 6 entries in the worked example
    best = by_serial.get(entry.serial_number)
    if best is None or rank[entry.transport_layer] < rank[best.transport_layer]:
        by_serial[entry.serial_number] = entry
cameras = list(by_serial.values())                 # 3 entries
assert len(cameras) == 3
assert len({c.serial_number for c in cameras}) == 3

The two asserts are the acceptance test: one entry per camera and no serial twice. If you also need the interface list, enumerate camera interface names with an index loop shows the pattern that keeps interface and device indices aligned.

Why does opening the second entry fail with an access error?

Because the first entry already owns the camera: machine-vision cameras open exclusively, so a second open of the same physical device is refused — the access error is a symptom of the duplicate, not a permissions fault on the PC.

The signature is precise: the loop opens the first entry, then fails on its twin. The same exclusive rule refuses a second client — a viewer left open holds the camera exactly the same way, so close other clients before blaming the list. Fix the order of operations: dedupe by serial first, then open, and never wrap the failed open in a retry loop, because retrying an ownership conflict only repeats it. The same claim rule bites USB too — failed to claim a USB interface: one client owns a USB3 Vision camera — and the cure is the same: one owner.

How do I keep this from coming back on the next machine?

Ship one SDK generation with the program, pin its transport layer path list in the deployed configuration, and write serial number plus interface ID into the first log line at startup — duplicates then cannot form, and any regression names itself in that line.

  • One SDK generation per program; the other generation stays installed only for programs that still need it.
  • Deploy the restricted configuration file with the code instead of editing each machine by hand.
  • Dedupe by serial before any open call, in every program, even after the count looks right.
  • Log serial and interface ID at startup, one line per camera.
  • Wire one camera per NIC port and one subnet per camera.
  • After any SDK update, count entries before the line runs.

For 10GigE cameras the one-port rule is the same: a quad-port copper 10GbE card such as the MV-GT2104 gives each camera its own interface ID and its own bandwidth.

Frame grabbersHikrobot MV-GT2104 Quad-port copper 10GbE NICMV-GT2104
Interface
10GigE
Ports
4 ports
$1,429.00View partBuild a system with it

Beyond wiring, the systems topic page collects the neighbouring failure modes, and the camera finder lists cameras by interface type when a station grows. If a production machine is stuck, send the serial-and-interface printout from the fourth section through the contact page — it names the layer that is doubling your list.

Questions

Can I delete the old SDK's transport layer files instead of editing the configuration?

You can, but edit the path list first: another program on the same machine may still depend on the old generation. If you do remove it, run its own uninstaller rather than deleting files by hand, with the line stopped, then re-run discovery and confirm the entry count equals the number of cameras on the bench.

Does the same duplicate happen with USB3 Vision cameras?

Yes. Any camera reachable through two transport layers lists twice — two SDK generations, or a vendor-specific layer installed beside the standard USB3 layer. The serial-number dedupe is identical, and on shared USB controllers also budget bandwidth per controller, because two full-resolution streams on one root hub behave like one overloaded interface.

Why did the duplicate appear only after I updated the SDK?

Newer API generations commonly load every transport layer installed on the system unless the path list says otherwise; the older generation kept to its own layers. The update widened the discovery scope — your camera count never changed. Set the path list to a single layer and the count returns to one entry per camera.

Should I open the camera through both transport layers for redundancy?

No. A machine-vision camera is opened exclusively, so the second transport layer's open is refused outright; there is no shared or standby handle. Build redundancy at the interface level instead — a second network path or a second camera, each a separate entry selected by serial number.

Will restricting the transport layer path list change my camera settings?

No. The path list only decides which transport layers load at API startup; GenICam feature settings, packet size and the camera's IP configuration are untouched. It does require a program restart, because the list is read once when the API initializes, not on every discovery call.