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
- 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.
- QuickFIX calls fromApp, your code calls something like
getString(LastPx.FIELD)orreport.getLastPx(), and the field is absent. - 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.
- The message counts as processed: its sequence number is used and it is not delivered again.
| Engine | Text (58) of the reject |
|---|---|
| QuickFIX/J | Conditionally Required Field Missing, field=31 |
| QuickFIX C++ | Conditionally Required Field Missing (31) |
| QuickFIX/n | The 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 hasgetOptionalString(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.
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
- QuickFIX/J source: Session.java (setting names, defaults, logout and reject texts)
- QuickFIX/J source: MessageCracker.java
- QuickFIX/J user manual: Receiving messages
- QuickFIX/n source: Session.cs (reject handling, sequence texts)
- QuickFIX C++ source: Session.cpp (reject handling, sequence texts)
- 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
- QuickFIX/J vs QuickFIX/n vs QuickFIX C++: Which One to Use
- QuickFIX Session Settings Explained: Configuration Reference
- QuickFIX with FIX 5.0 SP2: FIXT.1.1, Transport and Application Dictionaries
- Custom Fields and a Custom Data Dictionary in QuickFIX
- Repeating Groups in QuickFIX: Reading, Writing and Validation Errors
- QuickFIX Session Schedules: Daily vs Weekly Sessions, Time Zones and Sunday to Thursday Markets
- QuickFIX "Tag not defined for this message type": Causes and Fixes
- QuickFIX "Incorrect data format for value": Field Types and Fixes
- QuickFIX "MsgSeqNum too low": Reset Sequence Numbers Safely and Fix the File Store
- QuickFIX Logon Problems: Session Not Found, CompID Mismatch and Rejected Logons
- QuickFIX SSL and TLS: Setup per Engine and Handshake Failures
- QuickFIX onMessage Not Called: Message Cracking Problems
- Reading and Analyzing QuickFIX Logs: messages.log and event.log