ZagTrader

Garbled messages

Incorrect BodyLength (tag 9)

The value in BodyLength (9) does not match the number of bytes in the message body, so the receiver treats the message as garbled. Most engines drop it: no Reject is sent and the sequence number is not consumed.

What it means

BodyLength counts every byte after the SOH that ends the 9= field, up to and including the SOH before 10=. It counts bytes, not characters, and every SOH is one byte.

The receiver uses BodyLength to find the end of the message in the TCP stream. If it is wrong the receiver cannot frame the message, so the FIX rules say to ignore it rather than reject it. You see the effect one message later, as a sequence gap and a ResendRequest from the counterparty.

If every message has the problem, the session never gets past Logon: the counterparty drops the Logon and you see a timeout or a disconnect without a Logout.

Common causes

  • Counting characters instead of UTF-8 bytes. A non-ASCII character in Text (58) or a name field adds bytes.
  • Computing the length, then changing a field: adding SendingTime (52), rewriting CompIDs in a gateway, or adding PossDupFlag (43) and OrigSendingTime (122) on a replay.
  • Including the 8= and 9= fields, or the 10= field, in the count.
  • Leaving out the SOH after the last body field.
  • Building the message with | or ^ as the delimiter and swapping in SOH after the length was computed, or appending a line ending.

How to fix it

On the side that sent the message

  • Build the complete body first, then compute BodyLength over the final bytes, then CheckSum. Do both as the last step before writing to the socket.
  • Count bytes of the encoded message, not the string length your language reports.
  • Paste the message into the parser. It recomputes BodyLength and shows the expected value next to the one you sent.

On the side that raised the error

  • Log the raw bytes of dropped messages (most engines log them as invalid or garbled) and send them to the counterparty with the expected value.
  • Do not relax the check in production. Framing on a wrong length can merge two messages or cut one in half.

Example

The same New Order Single twice. The first has a BodyLength 4 bytes short; the second is correct. The parser flags the first one.

  1. 1. Wrong BodyLength

    8=FIX.4.4|9=138|35=D|49=BUYSIDE|56=SELLSIDE|34=57|52=20261020-09:30:00.010|11=ORD-1001|21=1|55=MSFT|54=1|60=20261020-09:30:00.000|38=1000|40=2|44=187.50|59=0|10=090|
  2. 2. Correct BodyLength

    8=FIX.4.4|9=142|35=D|49=BUYSIDE|56=SELLSIDE|34=57|52=20261020-09:30:00.010|11=ORD-1001|21=1|55=MSFT|54=1|60=20261020-09:30:00.000|38=1000|40=2|44=187.50|59=0|10=085|

SOH (0x01) is shown as |. BodyLength (9) and CheckSum (10) are calculated as if every | were SOH, except where the example is about a wrong value.

Open this example in the parser

Questions

How do I calculate FIX BodyLength?
Take the bytes that follow "9=<value><SOH>" up to and including the SOH that comes just before "10=", and count them. Use the encoded bytes, so a two-byte UTF-8 character counts as two.
Why did I get no Reject for a bad BodyLength?
Because the receiver cannot be sure where the message ends, it cannot trust any field in it, including MsgSeqNum. The FIX session rules therefore say to discard a garbled message silently.

Reference

Related errors

All FIX errors · FIX guides