OPC UA Browse Continuation Points: Bound Large Address-Space Discovery
A Browse continuation point is an opaque server-issued handle for unfinished results. Keep it with the originating Session and browse operation, replace it with the handle returned by each BrowseNext response, and explicitly release the latest handle when abandoning the operation. A small gateway needs bounds on outstanding operations and accumulated references as well as a page-size request.
This guide pins OPC UA Part 4, Services, version 1.05.07, sections 5.9.2, 5.9.3, 7.6 and 7.9. It covers Session-based Browse/BrowseNext. Session-less services, HistoryRead continuation and QueryNext are outside scope. An original reduced iterator model was executed; no server resource consumption or SDK iterator was measured.
Track one state record per starting operation
A Browse request can contain multiple starting nodes. Results match those operations in size and order, and each can have its own status, references and continuation point. Do not attach one global continuation handle to an entire multi-node request.
Use a record containing the Session generation, original browse description, current continuation bytes, accumulated-reference budget, page count, deadline and completion state. The original description includes direction, reference type, subtype selection, node-class mask and requested result fields.
The handle is a ByteString, not a string to parse for an offset or modify to request another page. A server can encode its continuation state into the handle or retain state internally. Its implementation is deliberately opaque to the client.

Choose bounded requests
requestedMaxReferencesPerNode limits returned references for each starting node. Zero means the client imposes no limit; it is not a request for zero references. A server may return fewer references than requested.
With several starting nodes, the maximum returned-reference count can multiply. It also does not bound the encoded byte size of arbitrary names and other returned fields. Choose an operation-count ceiling, a per-node reference ceiling and supported transport/decoder limits together.
Request only fields needed for the discovery task through resultMask. Stream accepted references into a bounded consumer or validated store rather than accumulating the entire address space in RAM. Stop visibly when a local node, byte, page or time budget is reached.
Drive the iterator from the continuation, not page length
Part 4 permits Browse to return no references with a continuation point when processing all requested work would take too long. Therefore zero references does not by itself mean exhaustion.
- Match each BrowseResult to its requested starting node and inspect its operation status.
- Validate and consume the returned references within local limits.
- If the continuation point is empty, finish that operation with its actual completeness status.
- If a point remains and work is allowed, issue BrowseNext on the same Session.
- Replace the saved handle with the handle from that response before the next continue or cancel decision.
- If work is abandoned while a handle remains, call BrowseNext with releaseContinuationPoints true.
A BrowseNext request can mix handles from different earlier responses, provided their Session requirement is satisfied. Keep an ordered mapping back to each local operation. Do not infer ownership from identical-looking reference lists or a shared starting-node label.
Make release a real lifecycle path
With releaseContinuationPoints true, the supplied points are released and the results and diagnostic arrays are empty. A client must not reject that response merely because it lacks one normal BrowseResult per submitted handle.
Release on user cancellation, local budget exhaustion and errors in downstream consumption when the Session remains usable. Use the most recently returned point. A handle from an earlier page may have been replaced, and replaying it is not a portable cancellation strategy.
If communication fails during release, report cleanup as uncertain and let the Session lifecycle or a supported SDK cleanup mechanism resolve it. Do not invent a successful release acknowledgement. Points remain active until completion, release or Session closure, subject to the server’s replacement behavior for limited resources.
Recognize continuation pressure
Servers support at least one continuation point per Session and advertise supported limits through ServerCapabilities. When new requests need space, a server can free continuation points from prior requests in that Session. A later attempt to use one then returns Bad_ContinuationPointInvalid.
Complete paused operations before starting more whenever practical. Bound parallel Browse operations by the supported continuation capacity instead of maximizing concurrency blindly. A server can return Bad_NoContinuationPoints for remaining operations when a new multi-operation request uses the available points.
Continuing an existing paused operation is different: section 7.9 says the server should reuse the supplied point and shall not return Bad_NoContinuationPoints for that continuation. Preserve the distinction in logs; it helps identify whether the client exhausted new-operation capacity or encountered an unexpected server behavior.
Restart invalidated work honestly
After Bad_ContinuationPointInvalid, discard the unusable point. If the discovery task permits it, restart the original Browse under a bounded retry policy and deduplicate references using their actual identities and relationship fields.
Restarting does not establish a snapshot of a changing address space. Nodes and references can change between attempts. Label the result as incomplete or unstable when the task cannot obtain its required consistency, rather than merging arbitrary pages into a supposedly authoritative inventory.
Likewise, preserve Uncertain_NotAllNodesAvailable instead of treating any nonempty result as complete. This status can report missing subsystem results independently of continuation handling.
An executed miniature campaign
The hypothetical iterator starts with reference N1 and token A. Continuing A returns an empty page and token B. Continuing B returns N2 and an empty token. The model reached both references in two continuation calls; an implementation that stopped at the empty page would miss N2.
A second path cancels after the empty page and records release of B. Reusing that released token is rejected in the model. A static restart fixture suppresses duplicate N1 and accepts N2. These tests exercise local ownership and control flow; they do not claim actual server handle encoding, allocation or snapshot behavior.
Acceptance on the selected server should include empty intermediate pages, multiple starting nodes, cancellation, limited continuation capacity, Session replacement and invalid handles. The deliverable is a bounded iterator whose remaining work and cleanup state can be explained at every exit, including failure.