Understanding v2 Acknowledgements

Almost always, when you send an HL7 v2 message, you need or get an acknowledgement message back from the destination system. This post describes how these acknowledgements work.


There’s 2 main uses for acknowledgement messages:

  • You need some content returned from the destination (i.e. accepting an order, getting an answer to a query)
  • You simply need to know that the message was received and processed without error

There’s a few corner cases where you don’t even need acknowledgement – the sender simply doesn’t care whether the receiver gets it or not. In the real world, the only case that I’ve seen for this is a vital signs monitor that sends an observation message with the current vital sign measurements once every minute. It’s assumed that some other system will raise an alert if the messages aren’t getting through. In every other case I’ve seen, there’s some kind of acknowledgement.

Response message

Each HL7 v2 message Event has a defined message type, and also a defined response message type. The most common response message is the simple ACK message:

That’s the v2.6 version, with the SFT and UAC segments that I’ve never seen in production. Otherwise, it’s got a message header (MSH), the MSA segment, which summarises the acknowledgement status of the message, and it may have one or more ERR segments that list specific issues in the message. I have seen ERR segments in production, but not often.

There are response messages with a much more complicated structure, such as the response to an R02 event, which is a full blown order message with an MSA added – a query for an order. In this post, I’m solely going to deal with the issues around message level acknowledgements.

MSA Segment

The MSA Segment has the following fields:

 # Description Data Type Table
1 Acknowledgment Code ID: Coded Value for HL7 Defined Tables Acknowledgment code (0008)
2 Message Control ID ST: String Data
3 Text Message ST: String Data
4 Expected Sequence Number NM: Numeric
5 Delayed Acknowledgment Type -: withdrawn
6 Error Condition CNE : Coded with No Exceptions Message error condition codes (0357)

The first field contains the acknowledgement code, where the possible values are:

Code ID Description
AA 1 Original mode: Application Accept – Enhanced mode: Application acknowledgment: Accept
AE 2 Original mode: Application Error – Enhanced mode: Application acknowledgment: Error
AR 3 Original mode: Application Reject – Enhanced mode: Application acknowledgment: Reject
CA 4 Enhanced mode: Accept acknowledgment: Commit Accept
CE 5 Enhanced mode: Accept acknowledgment: Commit Error
CR 6 Enhanced mode: Accept acknowledgment: Commit Reject

I’ll discuss the enhanced mode acknowledgement below. So you can receive 3 different kinds of codes:

  • Accept – the message was accepted without error
  • Error – the message had an error and was rejected
  • Reject – the message was rejected because of an error

I’ve always wished that there was some consistent difference between “error” and “rejection”, but I’m not at all sure what it is. In fact there’s no particular definitions of these two concepts. The best I can find is that a reject (CR) is returned if the one of the values of MSH-9-message type, MSH-12-version ID or MSH-11-processing ID is not acceptable to the receiving application, and an error is returned if the message cannot be accepted for any other reason (e.g., sequence number error). However this is rather confused by the table of values for MSA-6:

Code ID Description
0 1 Success: Message accepted
100 2 Error: Segment sequence error
101 3 Error: Required field missing
102 4 Error: Data type error
103 5 Error: Table value not found
200 6 Rejection: Unsupported message type
201 7 Rejection: Unsupported event code
202 8 Rejection: Unsupported processing id
203 9 Rejection: Unsupported version id
204 10 Rejection: Unknown key identifier
205 11 Rejection: Duplicate key identifier
206 12 Rejection: Application record locked
207 13 Rejection: Application internal error

I don’t know how to make systematic sense of this. If the database is down, so you can’t accept the message, should you return an error, or a reject? Beats me. And in practice, implementers seem to pretty much toss a coin. I think I’ve seen more AEs than ARs, on about a 4:1 ratio.

Processing Failures

I find this particularly frustrating because the question I always need to ask when I get an AE or an AR back is simple: should I send this message again?

In practice, the single most common cause of a message error/rejection being returned is some transient system error. Things like:

  • database is down / backing up
  • message handling process has become corrupt
  • deadlock contention
  • network unavailability

In all these cases, the correct thing to do is wait a while, and resend the same message again, and to keep doing so until it succeeds. If, on the other hand, the destination is working as expected, and there’s some content problem with the message, then what you want to do is to discard the message, make an entry some error log, and move on. So how can you tell the difference? Well, there’s no general method, and quite often, you can’t. I think this is one of the worst aspects of HL7 v2 messaging.

As a follow up to this, there’s a related question: do I need to send the messages in order or not? This is also a rather difficult question. There’s no technical requirement anywhere in the HL7 standard I know of that says that messages have to be delivered in order, but the messages reflect a series of transactions, and these generally do need to be delivered in order. Consider the following scenarios:

  • An ADT feed pushing patient and episode updates out. What happens if you drop a patient merge message, and then send it later, after other transactions on the patient record? (and in practice, merge messages are particularly prone to cause issues)
  • A results feed from a lab to an EHR. Lab results are amended periodically. What happens if you hold a message, and then release it – will it overwrite an subsequent version of the same lab report that was sent later?

In practice, this depends on the fine details of the identity and timestamp processing of the receiving system. HL7 has made no rules about how this works, so you can take nothing for granted. In practice, most v2 processing feeds are unreliable and fragile in this regard, whether from big or small vendors (that’s my experience) so it’s best to be very conservative unless you specifically know otherwise : If you get an error, hold everything until some knowledgeable human intervenes. Assuming, of course, that there is one available… where as there very often isn’t.


I’ve run out of time for now. I’ll make a follow up post that deals with enhanced mode acknowledgements, with the impact of intermediaries, and with a commentary about the sequence number protocol.





  1. Anonym says:

    There is a consistent difference between “error” and “rejection”. “Error” should be returned when the issue is inherent to the message (i.e. the message does not fully respect HL7 standard), while a “Rejection” is related to the receiving application (either it does not support the message type, its database is not ready, or there was an exception.

    I think the code AE (Error) should only be used with codes 100 to103 and AR (Reject) only with codes 200 to 207, as suggested by the description.

  2. Pablo Pazos says:

    Recently I found a case in which two ACKs are sent for the same received message, and I always thought just one ACK should be sent for each received message.

    In chapter 10 Scheduling of HL7 v2.5, for the SRM description it says: “When the filler application receives the transaction, it acknowledges it with the appropriate accept acknowledgment using an ACK message”, then “After processing the request at the application level, the filler acknowledges the transaction with the appropriate application acknowledgment in an SRR message”.

    So it seems ACK and SRR (ACK + scheduling stuff) are sent for the same SRM.

    Do you know if this is something common and if there are other cases of two ACKs per received message? Thanks.

    • Grahame Grieve says:

      This is the enhanced acknowledgement mode documented in chapter 2, section 2.3.3. It’s not widely used in practice.

    • Chintan Lakhavara says:

      Respected Sir/Madam,

      We are receiving HL7 Message like.

      ” MSH|^~\&|PRAXIFY|MHW|LIS|MHB_MHW|20170419145722||ORM^O01|1486442962507|P|2.3.1″ & vbCr &
      “PID|||MH001111414^^^Manipal Hospitals^MRN||SHETTY^Bhavana^^^Mrs||19860317000000|F|||^Flat No- S03 LaKe City Residency NeaR Garden City College k r Puram ^^^^India||9740837867^PRN^CP~^NET^X.400^shettybhavana@gmail.com|||||” & vbCr &
      “PV1|1|O|||7226057||mhwdc024^^Tasneem N Shah||mhwdc024^^Tasneem N Shah||||||||||O10000008147|||||||||||||||||||||||||20170417094900” & vbCr &
      “ORC|NW|93170290295||93170290295|H||1^^^20170419145722||20170419145722|||mhwdc024^^Tasneem N Shah|||20170419145737” & vbCr &
      “OBR|||| B0063^SDP- Apheresis Platelets – Reserve/Crossmatch|20170419145722|||||S|||||mhwdc024^^Tasneem N Shah|||||||||||1^^^20170419145722″ & vbCr &
      ” ” & vbCr & “”

      And We are sending ACK Message Like.

      ” MSH|^~\&|||PRAXIFY|MHW|20170419145722||ACK|1486442962507|P|2.3.1″ & vbCr & “MSA|AA|1486442962507″ & vbCr & ” ” & vbCr & “”

      But the status over their is showing discarded only instead of Completed.

      So,can you help us out, what is the problem of our ACK Message?

  3. Pablo Pazos says:

    Thanks for the info Grahame. I never used it before, I just saw this kind of transaction mentioned in the Schedule domain.

    BTW, congratulations for the great initiative of collaboration between FHIR and openEHR!

  4. PC says:

    In our implementation, which thousands of integrated clients are using, the MSA NACK response with code “AR” is used to indicate the application has rejected this message because it is a bad message (it could be because of format, missing data, etc.). In this scenario DO NOT retry or resend this message without fixing the message.

    The “AE” response is an application error message, which can be returned for a variety of reasons. Depending on the actual response, some can be retried (i.e. if service is not available, or database error, etc.), and some should not be retried (invalid content).

    We almost always use AR when we do not intend to have the message retried. We use AE when a retry could potentially result in success.

  5. Andrew Cope says:

    What if you’re a receiving application and the message is corrupt so that you can’t get the Message Control ID (MSH-10) from it?

    What would you put in the ACK to indicate to the sender which message you’ve had a problem with? Or in that case does the receiver send no response and hope that the sender will just try again?

Leave a Reply

Your email address will not be published. Required fields are marked *

question razz sad evil exclaim smile redface biggrin surprised eek confused cool lol mad twisted rolleyes wink idea arrow neutral cry mrgreen


%d bloggers like this: