ZagTrader

QuickFIX "Conditionally Required Field Missing": Why Your Handler Caused It

Written and maintained by ZagTrader. Last reviewed . How this page is sourced and checked

This reject is rarely the counterparty's fault in the way it sounds. In QuickFIX/J, QuickFIX/n and QuickFIX C++, a Business Message Reject with 380=5 is sent when the application callback (fromApp or a cracked onMessage handler) throws a field-not-found exception. In plain terms: your code asked for a field the message does not have, and the engine reported that to the counterparty.

What happens inside the engine

  1. A valid message arrives and passes the dictionary checks. A field required by the dictionary but missing would have been rejected earlier, with a session Reject and 373=1.
  2. QuickFIX calls fromApp, your code calls something like getString(LastPx.FIELD) or report.getLastPx(), and the field is absent.
  3. The exception reaches the engine. On FIX 4.2 and later it answers with Business Message Reject (35=j), 380=5, RefMsgType (372) and RefSeqNum (45) pointing at the message. On older versions, or for session messages, it sends a session Reject with 373=1 instead.
  4. The message counts as processed: its sequence number is used and it is not delivered again.
EngineText (58) of the reject
QuickFIX/JConditionally Required Field Missing, field=31
QuickFIX C++Conditionally Required Field Missing (31)
QuickFIX/nThe reason text only, without the tag number

Why it matters

Step 4 is the risk. If the message was an Execution Report (35=8) carrying a fill and your handler failed on an optional field, the fill was rejected at business level and your system did not book it. The counterparty may treat the reject as information only. Search the outgoing messages log for 35=j after every incident.

How to fix it

  • Read optional fields only after checking them: isSetField(tag) in QuickFIX/J and QuickFIX C++, IsSetField(tag) in QuickFIX/n. QuickFIX/J also has getOptionalString(tag), which returns an Optional.
  • Generated classes have a check per field, such as report.isSetLastPx() in QuickFIX/J.
  • Look at which fields the counterparty actually sends per message and ExecType (150). For example LastPx (31) and LastQty (32) appear on fills, not on acknowledgements or cancels.
  • Reading a group entry that does not exist (index 0 or past the count) throws the same exception. Loop from 1 to the count. See repeating groups.
  • If the field really is required for your business, reply with your own reject that says so, rather than letting the engine send a generic one.
QuickFIX/J: read an optional field safely
public void onMessage(quickfix.fix44.ExecutionReport report, SessionID sessionID) throws FieldNotFound {
    if (report.isSetLastPx()) {
        double lastPx = report.getLastPx().getValue();
        // book the fill
    }
    String text = report.getOptionalString(Text.FIELD).orElse("");
}

When you receive the reject

If your counterparty runs QuickFIX and sends you this reject, their handler expected a field you did not send. Read Text (58) for the tag number, then check their specification: the field is often conditionally required, for example Price (44) on a limit order or StopPx (99) on a stop order.

Questions

What is BusinessRejectReason 5?
Conditionally required field missing. QuickFIX sends it when application code reads a field that the message does not contain.
Why does QuickFIX send a Business Message Reject instead of a session Reject?
The message passed session validation, so the problem is at business level. On FIX 4.2 and later QuickFIX reports exceptions from the application callback with 35=j.
Is the rejected message resent?
No. Its sequence number is used, and the counterparty sees the reject. Check whether it was a fill you needed to book.

The FIX side of the problem

What the error means on any FIX engine, with example messages you can open in the parser:

Reference

Sources

  1. QuickFIX/J source: Session.java (setting names, defaults, logout and reject texts)
  2. QuickFIX/J source: MessageCracker.java
  3. QuickFIX/J user manual: Receiving messages
  4. QuickFIX/n source: Session.cs (reject handling, sequence texts)
  5. QuickFIX C++ source: Session.cpp (reject handling, sequence texts)
  6. QuickFIX C++ documentation: Receiving messages

Setting names, defaults and message texts were checked against the projects' source code and documentation on the review date shown at the top of the page. Behaviour can change between releases; check the version you run. This guide is independent and not affiliated with the QuickFIX projects.

See also

More QuickFIX guides