Sequence numbers and recovery
SequenceReset: GapFill (123=Y) vs Reset mode
SequenceReset (35=4) moves the receiver's expected inbound number forward. In GapFill mode (123=Y) it stands in for messages that will not be replayed. In Reset mode it is an emergency override. Neither mode can move a number backwards.
What it means
GapFill mode (123=Y) is part of answering a ResendRequest. Its MsgSeqNum (34) is the first number being skipped and NewSeqNo (36) is the number of the next message the sender will send. It carries 43=Y like any other replayed message, and its sequence number is checked like any other.
Reset mode (GapFillFlag (123) absent or N) is for recovery when messages cannot be replayed at all. The receiver ignores its MsgSeqNum and sets the next expected number to NewSeqNo (36). Use it rarely and tell the counterparty, because whatever lay in the skipped range is lost.
If NewSeqNo (36) is lower than the number the receiver expects, the receiver rejects the SequenceReset with 373=5 (value incorrect) and keeps its counter. Lowering sequence numbers needs a Logon with 141=Y, which resets both directions to 1.
Common causes
- GapFill sent with a MsgSeqNum lower than expected and without PossDupFlag=Y: the receiver logs out with "MsgSeqNum too low".
- GapFill with NewSeqNo pointing past the messages that follow it, so real messages are skipped.
- GapFill with NewSeqNo equal to its own MsgSeqNum, which moves nothing and leaves the gap open.
- Reset mode used to lower the counter, which is rejected with 373=5.
How to fix it
On the side that sends the SequenceReset
- In answer to a ResendRequest, use GapFill only. Set MsgSeqNum (34) to the first skipped number and NewSeqNo (36) to the next real message's number.
- Use Reset mode only after agreeing it with the counterparty, and only to move forward.
- To start both sides at 1, log on with 141=Y instead.
On the side that receives it
- Accept a GapFill only when its MsgSeqNum is the one you expect (or lower with PossDupFlag=Y).
- For Reset mode, ignore MsgSeqNum and apply NewSeqNo if it is higher than expected; reject it otherwise.
Example
A GapFill answering a ResendRequest, and a Reset-mode message moving the counter forward to 500.
1. GapFill: replaces 101 to 104, next message is 105
8=FIX.4.4|9=104|35=4|49=SELLSIDE|56=BUYSIDE|34=101|52=20261020-10:15:02.132|43=Y|122=20261020-10:15:02.132|123=Y|36=105|10=018|
2. Reset mode: next expected number becomes 500
8=FIX.4.4|9=73|35=4|49=SELLSIDE|56=BUYSIDE|34=106|52=20261020-10:20:00.000|123=N|36=500|10=232|
SOH (0x01) is shown as |. BodyLength (9) and CheckSum (10) are calculated as if every | were SOH.
Open this example in the parserQuestions
- What is the difference between SequenceReset and ResetSeqNumFlag?
- SequenceReset changes only the receiver's expected inbound number, and only upward. ResetSeqNumFlag (141=Y) on a Logon sets both sides' counters in both directions back to 1.
- Does a GapFill need PossDupFlag?
- When it answers a ResendRequest its MsgSeqNum is lower than the receiver's high-water mark, so it needs PossDupFlag=Y and OrigSendingTime like any replayed message.