OPC UA Republish: Recover Notification Gaps Without Claiming Unlimited Replay
Republish retrieves a particular sent NotificationMessage while the server still retains it. It cannot reconstruct changes discarded before publication, recover an expired Subscription, or promise unlimited replay. A useful client recovery procedure distinguishes a recoverable message gap, the normal end of available messages, and a confirmed hole requiring explicit resynchronization.
This guide pins OPC UA Part 4, Services, version 1.05.07, sections 5.14.1, 5.14.5, 5.14.6 and 6.7. Its scope is ordinary Subscription retransmission and client bookkeeping. Durable Subscriptions, persistent gateway storage and Subscription transfer qualification are separate topics. The executed fixture is a logical application model, not a server or SDK test.
Keep a Subscription-scoped receive ledger
Track the server context, Subscription identity and a local Subscription generation together with the next expected message sequence. Never reuse a receive ledger solely because a newly created Subscription happens to receive the same numeric identifier.
NotificationMessage sequence numbers are unsigned 32-bit values. They start at one, increment for messages and wrap from the maximum value back to one; zero is never used. The sequence is not reset during a Subscription’s lifetime. Use a supported bounded sequence-order algorithm rather than an ordinary greater-than comparison across rollover.
A keep-alive carries the sequence number of the next NotificationMessage. It does not consume that data-message sequence. Record it as liveness evidence without marking the sequence received or acknowledging it as a delivered data message.

Separate acknowledgement from future availability
Publish requests carry Subscription acknowledgements. The server may delete an acknowledged message from its retransmission queue. Treat acknowledgement as releasing that recovery opportunity, and use the selected SDK’s documented receive/acknowledgement behavior rather than inventing an unsupported storage guarantee.
The Publish response reports acknowledgement results in the same order as the submitted acknowledgements. Check those operation results independently of the new notification payload. Bad_SequenceNumberUnknown is an acknowledgement result; Bad_MessageNotAvailable is a Republish result. Combining both into one vague “sequence error” hides which operation failed.
The response’s availableSequenceNumbers is diagnostic availability evidence prepared after processing acknowledgements. It is not a reservation. A message advertised there can be removed before the later Republish request, including through retransmission-queue overflow, which deletes the oldest sent message.
This version permits servers without retransmission-queue support and specifies an empty availability list for that case; it says the client should not acknowledge sequences when the list is empty. Qualify the server’s actual profile and SDK behavior before making recovery support a product requirement.
Recover before replenishing normal Publish traffic
Section 6.7 specifies reconnect handling that first restores the channel and activates the existing Session where possible. After re-establishing the connection, the client calls Republish in a loop starting at its next expected sequence and increments until Bad_MessageNotAvailable. It then starts normal Publish handling. This ordering avoids new Publish responses overwriting the retained messages being recovered.
- Restore the existing Session through the supported SDK recovery path and confirm that the Subscription is still valid.
- Enter a serialized recovery phase with the correct Subscription generation and next expected sequence.
- Request that exact sequence, validate the response and deduplicate before exposing application effects.
- Record accepted history, advance the expected sequence with zero skipped, and request the next message.
- On Bad_MessageNotAvailable, end the loop and classify any already established gaps before resuming normal Publish handling.
- On Bad_SubscriptionIdInvalid, leave message recovery and recreate the Subscription through the product’s explicit recovery procedure.
Bound memory, request deadlines and total recovery effort. If local limits prevent completion, expose an incomplete-recovery state and choose a documented resynchronization policy. A local timeout does not prove that missing history was recovered. Do not silently declare success because a retry budget ended.
Interpret the unavailable message in context
In the hypothetical executed fixture, the client expects sequence twelve and the server retains twelve and thirteen. Republish returns both; requesting fourteen returns Bad_MessageNotAvailable. With no evidence that fourteen was previously sent, this is the normal end of the available recovery run.
In a second case, the client has already observed thirteen but lacks twelve. If twelve is unavailable, the same service result leaves a confirmed hole. Resuming delivery may restore fresh values, but the ledger must retain the historical gap.
A third case advertises twelve, then removes it before the request. The model returns unavailable. This demonstrates why an earlier availability observation cannot substitute for the actual Republish result. Real server eviction timing and queue capacity were not measured.
Resynchronize state without inventing history
When a known missing message cannot be recovered, section 6.7 recommends ResendData or reading the data MonitoredItems’ values. Use those supported mechanisms to repair the client’s state view, while marking unrecovered history explicitly.
ResendData is not a promise of one simultaneous fresh snapshot. The specified behavior can deliver the next queued value for an item or repeat its last sent value if nothing is queued. A multi-node Read likewise needs its own consistency contract. Neither operation recreates an event or intermediate transition that has already been lost.
Keep historical insertion separate from replacement of the latest-state cache. An older recovered notification must not overwrite newer data already present in the client. Sequence alone orders Subscription messages, not every physical source observation across independent Subscriptions; retain per-item timestamps, quality and the application’s accepted ordering policy.
Qualification checklist
The local model checked recovery of twelve and thirteen, a known missing twelve, eviction after an availability observation, invalid Subscription identity, rollover skipping zero, keep-alive handling and protection of a newer cache value from older recovered history. It did not simulate wire acknowledgements, cryptography or a complete modular ordering algorithm.
On the selected server and SDK, repeat those cases with controlled disconnects, bounded queue pressure and explicit response capture. Verify exactly when the SDK acknowledges, how it serializes reconnect recovery, and how it reports unrecoverable gaps. Acceptance is a ledger that explains recovered messages, known loss and current-state repair separately, without turning bounded retransmission storage into an unlimited replay claim.