Why Orders Get Rejected
An order can be turned away at several different checkpoints — malformed message, risk limit, exchange business rule — and knowing which one rejected it is the difference between a five-second fix and an afternoon of confused debugging.
Prerequisites: FIX Message Types And The Tags That Matter
An order sent to an exchange passes through several checkpoints before it ever touches the matching engine, and each one can reject it for a different reason. Grouping rejects by where they happen, rather than treating "rejected" as one undifferentiated outcome, is what actually lets you fix the problem quickly.
Session-level rejects
Before the message is even understood as an order, the FIX engine itself can reject it — a malformed tag, a missing required field, or a message that doesn't parse against the expected format. These come back as a plain Reject (tag 35=3) rather than an order-specific message, because the receiving system never got far enough to know it was looking at an order at all. This is usually a software bug on the sending side: a tag left blank, a field sent in the wrong format.
Pre-trade risk rejects
Before an order reaches the exchange, many firms run it through an internal or broker-provided risk gateway that checks things like maximum order size, maximum notional value, price collars around the current market, and available credit. A reject here means the order was syntactically fine but tripped a limit meant to catch fat-finger errors or breaches of a client's trading limits — these are deliberate guardrails, not bugs, and the fix is usually to adjust the order rather than the system.
Exchange business rejects
The exchange itself can reject an order that passes both earlier checks but violates a market rule: trading in that symbol is halted, the order type isn't supported for that instrument, the price is outside the exchange's own price bands, or the account isn't entitled to trade that product. These come back as an Execution Report with ExecType set to rejected, carrying a reason code specific to that venue.
Why the layering matters
A reject that never reaches the exchange (session or pre-trade risk) and a reject the exchange itself sent back look different in the logs and mean different things: one says "your order never got there," the other says "the exchange saw it and said no." Debugging starts by identifying which layer generated the reject, because chasing an exchange-side symbol code when the real problem was a malformed FIX tag wastes exactly the time that matters most when a strategy is trying to get an order live.
Order rejects happen at distinct checkpoints — malformed message (session layer), breached limit (pre-trade risk), or violated market rule (exchange) — and the fastest fix starts by identifying which checkpoint generated the reject rather than treating every rejection as the same problem.
Keep the exchange's reject reason code table on hand, and log which layer rejected an order (not just that it was rejected) — the two or three seconds it takes to check the layer usually saves far more time than guessing.
Related concepts
Practice in interviews
Further reading
- FIX Trading Community, FIX 4.4 Specification, Volume 2