A capture script that runs cleanly for half an hour and then dies points at one habit: entering the camera API context, discovering devices and opening the camera inside the per-frame function. The error looks like a buffer problem — VmbError.MoreData (−9), raised from a camera-list call before any frame is grabbed. Below you get the meaning of the error, why the failure lands near cycle 1,000, the restructure that fixes it, two secondary checks and a pre-run checklist for the next long run.
What the −9 "MoreData" error actually reports
The SDK's error table defines the code as "more data available in a string/list than space is provided". It belongs to calls that fill a list the caller supplies: the function found more entries than the caller gave room for. It is not a frame error and not a timeout.
The failing stack names the call that ran out of room. Context entry starts the API, startup runs interface and camera discovery, and discovery ends in the enumeration call VmbCamerasList — that is where the exception surfaced in the reported run. Nothing on that stack touches get_frame, conversion or saving.
So when −9 appears only after hundreds of clean captures, the image path is innocent. A lost image packet announces itself as an incomplete frame; a failing enumeration pass announces itself exactly like this. What a camera and its software owe each other at this stage is set by the standard, described in camera compatibility with vision software: what GigE Vision guarantees.
Why per-frame open and close fails near cycle 1,000
Count what the failing structure pays for every 2-second capture: one context entry, one interface scan, one network discovery pass, one full feature enumeration, one open, one close. A GigE camera adds a UDP discovery exchange to those passes. About a thousand captures means about a thousand of each — with the camera's identity never changing.
Each pass allocates and frees handles, sockets and driver state on the host. When one of them comes back not quite clean, the deficit collects in the transport layer until the enumeration call starts returning contradictory results: more entries claimed than the buffer holds. The signature matches a leak — nothing fails early, failures arrive only after many cycles, and the count moves between runs, which is why the reported 1,000 is approximate rather than a rating.
The camera never needed any of it. One context entry, one lookup, one open covers a series of any length. Growth that shows up only after many loop iterations is a pattern beyond cameras; vision software memory leaks: find and fix inspection loop growth applies the same count-and-log method to your own buffers.
The three likely causes, tested in order
Work down the table and stop when a test changes the behavior.
| Rank | Cause | What points to it | Test | Fix |
|---|---|---|---|---|
| 1 | Session churn: context entry and discovery per frame | Traceback ends in VmbCamerasList during context entry; failure near cycle 1,000 and drifting |
Open and close in a tight loop, no grab, 2,000 iterations | One session for the whole series |
| 2 | Reused frame after conversion | Errors follow get_frame and conversion, not context entry |
Copy each frame before convert_pixel_format
|
Copy, convert the copy, save |
| 3 | Discovery or control packets lost on the link | Fails on one cable or port and not another; disconnects follow cable movement | Swap the cable; check firewall and adapter settings | Rated cable; UDP 3956 and 3957 allowed; jumbo packets on |
The isolation test for cause 1 takes minutes: a bare loop that enters the context, looks the camera up and closes, 2,000 times, with no grab and no delay beyond the loop's own cost. If the same −9 appears there, churn alone reproduces the failure, and the fix in the next section is the whole answer.
Failure on cycle 1 points elsewhere. Another capture tool still holding the camera blocks the open immediately; an open-sequence problem has its own fix path in camera failed to initialize error: fix the start sequence. A discovery that succeeds while the open fails is a separate case too — GenTL camera open failure after successful discovery — and a camera that vanishes mid-run belongs to diagnose single camera disconnects during capture.
The fix: one session open for the whole series
Restructure so the expensive work runs once and the loop only grabs:
- Enter the API context once, at program start, outside any per-frame function.
- Look the camera up once with
get_camera_by_id; the ID discovery prints is stable for that device. - Set exposure, gain and pixel format once, right after the open.
- Inside the loop, call
get_frame, copy the frame, convert the copy and save it. Nothing else touches the session. - Log a cycle counter with every frame, so any later failure carries a number.
- Leave the camera and the context once, after the last frame.
import copy
import time
import numpy as np
CAMERA_ID = "DEV_000000000000" # illustrative; use the ID your discovery tool prints
N_FRAMES = 2000 # int, frames in the series
INTERVAL = 2.0 # float, seconds between captures
with get_instance() as api: # context entered once for the whole run
cam = api.get_camera_by_id(CAMERA_ID) # opened once per series
cam.ExposureTime.set(30) # microseconds, written once
cam.Gain.set(27) # camera's own gain unit, written once
cam.set_pixel_format(PixelFormat.Mono8)
for i in range(N_FRAMES):
frame = cam.get_frame() # the only per-frame session call
image = copy.deepcopy(frame).as_numpy_ndarray()
np.save(f"frames/img_{i:05d}.npy", image)
time.sleep(INTERVAL)
# camera and context close once, here
The call names in the loop — get_camera_by_id, get_frame, set_pixel_format, ExposureTime, Gain — are the ones from the failing snippet; get_instance, the constants and the save path are illustrative. Types: CAMERA_ID is a string, N_FRAMES and INTERVAL numeric, image an array.
Prove it with a soak: 2,000 frames at the production interval, counter logging every cycle. The series that died near 1,000 now passes 2,000 with the enumeration call never re-entered. This is the same shape as a hardware trigger grab loop in Python: acquire and save each frame, and for event-driven capture, keep a camera open and ready between MQTT-triggered grabs applies the identical rule.
Worked example: cycle 1,000 of a 2-second capture series
Inputs, and where each comes from:
- Interval: 2 s between captures, as stated in the reported capture plan.
- Failure point: about 1,000 captures, reported to drift between trials.
- Context entries: one per capture in the failing structure.
- Session overhead: 50–200 ms per context entry for discovery and feature enumeration on a quiet host with one camera — an estimate, not a datasheet value.
The rule, in words: runtime to failure equals cycles times interval; discovery passes equal context entries; wasted session time equals cycles times per-entry overhead.
Decision: at a 2-second cadence the failure zone starts inside a shift — about 30 minutes, near cycle 1,000, is where the reported case died. Any series that can run unattended longer than about 30 minutes gets one session; only a tool that opens, grabs a handful of frames and exits may keep per-frame opens. If the traceback ends in the enumeration call, do the restructure before touching cables or conversion.
If one session still fails: two secondary checks
Copy the frame before conversion
Vendor guidance for the capture library states that a frame should not be reused for transmission once it has been converted: convert_pixel_format changes the object in place. Copy first — a deep copy is what the reported case tried — then convert the copy. In that run the copy alone did not clear the error because the stack pointed at discovery, but it is the correct way to convert and removes a second class of odd failures.
Check the physical link and the discovery path
Control and discovery traffic for a GigE Vision camera travels on UDP 3956 and 3957; a firewall without an explicit allow rule for both makes discovery flaky. Jumbo packets need enabling on the network adapter and on the camera, or long frames fragment. Disconnections that repeat trace back to the physical layer: an unstable connection, a damaged cable, poor connector retention, excessive movement.
For the swap test pick a cable built for the job — screw locks, drag-chain-rated flex — like the LS-CBL-0199.
On a fixed install with a longer run, the LS-CBL-0117 carries a locking-stud RJ45 over 15 m, which holds retention where a plain patch cable works loose. Compare lengths and connectors in the accessories finder.
- Type
- Camera data cables
- Length
- 15 m
More capture-pipeline diagnosis, camera side and host side, is grouped on the systems topic page.
When reopening a camera is actually correct
Three cases keep their opens:
- A one-shot tool that grabs a handful of frames and exits — the churn never accumulates.
- A handler that reopens after a hot-plug or device-change event, looking the new device up once by ID.
- A rig that adds cameras at runtime: each new camera opens once, on its own event.
A periodic series — logging every few seconds, production inspection, a timelapse — must hold one session, because its cycle count climbs without limit. One-shot capture has a failure mode of its own: software trigger image timeout: why one-shot capture misses frames. And when the process crashed or the camera lost power mid-run, recovery is a separate procedure — see GigE Vision image corruption after a camera power cycle and camera disappears after capture crash: diagnose USB recovery.
Pre-run checklist for a long capture series
- Context entered once per process, outside the loop — every entry re-runs discovery and feature enumeration.
- Camera opened once by ID, and the ID string matches what discovery prints.
- Exposure, gain and pixel format written once after the open.
- Every frame copied before
convert_pixel_format. - Cycle counter logged per frame, so any failure carries a number.
- Soak test of at least 2,000 cycles at production cadence passed.
- Firewall allows UDP 3956 and 3957; jumbo packets enabled on adapter and camera.
- Cable locked and rated for the install's length and flex.
If you are provisioning the capture station
The restructure costs nothing; the hardware side is one decision. A GigE area scan camera that discovery sees every time, on a cable that never works loose, keeps the enumeration quiet for the life of the series. The camera finder filters by interface, resolution and shutter; the MV-CU020-90GC, a 2.5 MP GigE camera with a global shutter, sits mid-range in that line.
- Sensor format
- 1/1.7"
- Lens mount
- C-mount
- Interface
- GigE
- Resolution
- Up to 3 MP
To size camera, cable and controller together, start the camera configurator. For a series that must run hours unattended, contact the applications team with the cadence and the runtime — the session structure follows those two numbers.
Questions
What does the −9 MoreData error actually mean?
The SDK's error table defines it as more data being available in a string or list than the space the caller provided. It is raised by calls that fill a caller-allocated list, such as the camera enumeration call. In a per-frame open structure the failing call is that enumeration, which runs inside context entry before any frame exists — so the error points at discovery, not at the image path.
How many open and close cycles are safe before the error appears?
Treat it as a when, not a rating. The reported case failed somewhere near 1,000 cycles and the count moved between trials; the exhausted resource varies with host, adapter driver and SDK version. Plan on failure within a shift for per-frame opens and remove them: one session per series makes the cycle count irrelevant, because discovery and open run once instead of a thousand times.
Does the same fix apply to a USB3 Vision camera?
Yes for the session structure: open once, configure once, grab in the loop, close once. USB enumerates on the local bus rather than over network discovery, so the failing resource and the cycle count before trouble differ, and recovery after a crash has its own path. The one-session rule and a logged cycle counter carry over unchanged.
Why didn't copying the frame before conversion fix the error?
Because the failing call sat in the discovery path, which runs during context entry, before get_frame was ever reached. The copy protects the conversion path, where a converted frame object must not be reused for a later transmission. Both fixes matter: the copy for clean conversions, the single session for the enumeration failure. Fixing one does not remove the other.
When is opening the camera per capture actually correct?
In a one-shot tool that runs, grabs a few frames and exits, and in handlers that reopen after a hot-plug or device-change event. Both reopen on a real event, not on a timer. A periodic series — logging every few seconds, production inspection — is the case that must keep one session open, because its cycle count climbs without limit.
Should exposure, gain and pixel format be set for every frame?
No. Set them once, right after the open. Each set is a control round trip — over the network for a GigE Vision camera — so per-frame sets add latency and traffic the series does not need. The reported structure reset all three on every capture; with one session they are written once and stay put for the whole run.


