OPC UA PubSub Delta Frames: Recover State After a Subscriber Misses Its Baseline
A cyclic PubSub delta frame supplies changes relative to earlier DataSet state. It cannot initialize missing fields or prove that skipped updates were irrelevant. Keep a per-writer reconstruction state, require a complete compatible key frame before using deltas, and invalidate that baseline when continuity is no longer established.
This guide pins OPC UA Part 14, version 1.05.06, published 22 October 2025. The procedure scopes UADP cyclic data with DataSetMessage sequence numbers and configuration versions enabled. Events, Actions, JSON-specific mapping and client-server Republish are excluded. An original post-decoding model was executed; no publisher, SDK or network loss experiment was run.
Define what the baseline contains
Keep the publisher/writer identity, validated metadata version, complete field vector, last processed data-message sequence and baseline-valid state together. A reconstruction table keyed only by topic or numeric writer identifier can mix unrelated publishers.
Part 14 distinguishes key frames containing all DataSet fields from delta frames containing fields changed since the previous DataSetMessage. UADP delta entries include FieldIndex, which refers to position in the corresponding DataSetMetaData. The publisher must not use the same index twice in one delta message.
A receiver joining between key frames has no values for omitted fields. Filling them with zero creates an invented process sample. Keep the reconstructed DataSet unavailable until a valid full key frame supplies the baseline.

Do not substitute the NetworkMessage sequence
A NetworkMessage can carry multiple DataSetMessages. Track the DataSetMessage sequence associated with the specific writer being reconstructed; a transport packet’s arrival counter is not automatically that sequence.
For UADP, this sequence is UInt16 and wraps to zero. Section 7.2.3 defines its modular ordering test using the value obtained from received minus one minus last, modulo 65,536. Values below 16,384 indicate newer messages; values above 49,152 indicate older or equal messages. The intervening range, including those bounds, is invalid for that comparison.
That ordering test does not prove continuity. A newer delta whose sequence skips the expected next value can still depend on a lost update. The local policy requires exact next-sequence continuity before applying a delta and ignores duplicates or older data rather than applying them twice.
Apply every delta atomically at the application boundary
- Validate message security, writer association, message validity and compatible metadata through the supported stack.
- Confirm that the message is a supported key frame, delta or keep-alive.
- For a delta, require a valid baseline and the expected next data sequence.
- Validate every field index, uniqueness, datatype and supported size before altering the published vector.
- Apply changes to a candidate vector or equivalent protected staging state.
- Publish the new coherent vector and sequence together only after all checks succeed.
A malformed last entry must not leave the first entries visible as a partly applied sample. The executed model specifically checks an out-of-range index after an otherwise valid update and a repeated index; neither changes its previous vector.
This is an application consistency policy, not a claim that every SDK exposes a ready-made transactional delta callback. Inspect where the actual library reconstructs values and whether application callbacks see individual changes or a coherent DataSet boundary.
A missed update can silently corrupt later reconstruction
In the hypothetical fixture, a key frame establishes three values: ten, twenty and thirty. A contiguous delta changes the second value to twenty-one; another changes the first to eleven. The current vector is eleven, twenty-one, thirty.
The receiver then misses a data message and sees a later delta changing only the third field. Applying it blindly would leave any lost changes to the first two fields undetected. The model rejects that delta as a usable reconstruction, retains the old vector only as unavailable historical state, and waits for a new key frame.
The next full key frame establishes twelve, twenty-two and thirty-three. It restores current state without claiming that the missing intermediate process history has been recovered.
Handle keep-alive without inventing a data update
Section 7.2.4.5.8 says a UADP keep-alive’s sequence field gives the next expected sequence for the DataSetWriter. It does not consume that data sequence. The fixture observes a keep-alive carrying four after data sequence three, then correctly accepts data sequence four.
Keep-alive reception can establish liveness and reset the applicable receive timeout, but it does not provide omitted field values or repair an invalid baseline. A next-sequence indication ahead of the receiver’s expectation is evidence to investigate a gap, not a replacement key frame.
Heartbeat DataSetMessages are a separate header-only configuration and are not full process-data baselines. This procedure requires a key frame containing the complete configured cyclic DataSet.
Choose key-frame and timeout behavior deliberately
KeyFrameCount is a multiplier of PublishingInterval that bounds the number of interval expirations before a key frame is sent for cyclic data. A value of one makes every message a key frame. If no values change, a delta frame is not sent.
Do not estimate recovery time by simply counting received delta packets. Packet loss, idle periods, transport scheduling and the configured key-frame interval all matter. A more frequent key frame can reduce expected resynchronization delay while increasing traffic; qualify that tradeoff on the actual deployment.
The specification requires discarding stored sequence records after two MessageReceiveTimeout periods without messages. The model also invalidates its usable baseline at the first timeout and requires a key frame after sequence reset. That stricter reconstruction policy prevents a restarted publisher’s first delta from inheriting stale fields.
Qualification evidence
The executed cases covered delta-before-key rejection, contiguous updates, keep-alive sequence preservation, loss followed by key-frame recovery, duplicate data, invalid and repeated indexes without partial effects, wrap from 65,535 to zero, silence-driven reset and metadata change. The sequence tests used the pinned modular comparison, rejecting both invalid-range bounds and older keep-alive indications without refreshing liveness. Repeated valid next-sequence keep-alives refreshed liveness without consuming the sequence.
Target tests must add real message security, encoding, reorder limits, transport loss, SDK callback behavior and processing-time bounds. Acceptance requires every exposed DataSet to have a known compatible baseline and continuity evidence. When either is missing, report unavailable reconstruction rather than silently carrying stale fields into a supposedly current sample.