GoodMoreData
GoodPartial result
GoodMoreData is not an error. The call succeeded and returned as much as fit; there is more. It appears mainly in HistoryRead, where a continuation point comes with it. Keep calling with the continuation point until it stops appearing, and release any continuation point you abandon.
What you actually see
A history query returns a plausible but short series that always ends at the same point, and a naive client concludes the data stops there.
Why it happens
- History query larger than the per-call limitServers cap how many values one HistoryRead returns, either by an explicit numValuesPerNode or by an internal response size limit. A month of one-second data will never come back in one call. The server returns the first block, this status, and a continuation point to pick up from.
- Client ignoring the continuation pointThe continuation point is the whole mechanism. Client code that reads the first result and moves on gets a truncated series with no error. This is why history queries so often appear to be missing older data that is in fact present.
- Response size limit reached before the value count limitLarge values - strings, structures, arrays per timestamp - reach the encoding or response size limit long before the value count does. The same query returns very different block sizes for different node types, which makes a hardcoded expectation about block size unsafe.
- Bounded time range with more values inside it than expectedA query for a narrow window can still overflow when the underlying data is dense, for example a value logged on every change during a fast transient. Block-based paging is required regardless of how small the requested window looks.
- Aggregate or processed read spanning many intervalsA processed history read over many processing intervals produces one value per interval and can exceed the limit just as a raw read can. The paging behaviour is the same, so the same loop must handle both.
How to fix it
In diagnostic order: work down, do not skip ahead.
- Loop on the continuation pointAfter each HistoryRead, check for a continuation point on each node's result. While one is present, issue another HistoryRead passing it back and appending the values. Stop when no continuation point is returned. Do this per node, since different nodes in one call complete at different points.
- Release continuation points you stop usingContinuation points hold server resources and servers cap how many can exist at once. If you abandon a query, issue the read with releaseContinuationPoints set so the server can free it. Otherwise you exhaust the pool and subsequent queries fail.
- Set numValuesPerNode deliberatelyAsking for a defined block size makes the paging predictable and keeps individual responses well inside the transport limits. A few thousand values per call is a reasonable starting point for simple numeric data; reduce it for structures and large strings.
- Guard the loop against non-terminationBound the number of iterations and the total values collected, and abort with a clear error if the timestamps stop advancing. A server bug or a misused continuation point can otherwise produce an infinite loop that looks like a hung client.
- Query in bounded time windows as well as pagingSplit a long report period into day or hour windows and page within each. That keeps memory use predictable, makes retries cheap, and gives you a natural checkpoint if a long extraction is interrupted.
Where it shows up, by tool and stack
| Tool / stack | What to do there |
|---|---|
| UA-.NETStandard (C#) | HistoryReadAsync returns a HistoryReadResult per node carrying the ContinuationPoint. The managed helpers page for you; hand-written calls must loop and must release abandoned points. |
| asyncua (Python) | read_raw_history takes a value count and handles the common paging case, but a very large extraction is better done as explicit windowed queries so memory and retries stay under control. |
| node-opcua | The history read result exposes the continuation point directly. Build the paging loop once as a helper rather than in each query site, and always release on abort. |
| Ignition | As a historian it serves history over OPC UA and applies its own per-call limits. Confirm you are receiving the full series by comparing a query against the same range viewed in the platform's own trend. |
| UaExpert | The History Trend View pages transparently, so it is a good control: if the tool shows a longer series than your client, your client is not following continuation points. |
| Eclipse Milo (Java) | The history read response carries a continuation point per node. Track completion per node rather than for the request as a whole, since nodes finish at different points. |
What it looks like in the log
HistoryRead returned 1000 values with GoodMoreData; continuation point present
Paging history for ns=3;s=Line1.Temp: block 7, 7000 values so far
Releasing continuation point for aborted history query
Confirm the fix
Confirm the assembled series covers the full requested range by checking the first and last timestamps against what you asked for, and confirm the value count is consistent with the logging rate rather than with a single block size.
Stop it happening again
Implement continuation-point paging once in a shared helper with a release path and an iteration bound, query long reports in bounded time windows, and assert coverage of the requested range before a report is considered complete.
Stuck on more than one of these? The troubleshooting clinic works through broken configurations end to end, on camera.
Troubleshooting clinic →Last verified 7 September 2026 against OPC UA 1.05.07. OPC UA Connect is an educational resource and is not affiliated with the OPC Foundation.