The MSG (Message Type) data type was introduced as a composite in HL7 v2.4. Before v2.4, MSH-9 carried three separate fields (Message Code, Trigger Event, Message Structure) glued together by position and convention; v2.4 promoted them to a single typed composite, MSG, with three explicit components. From v2.4 onwards, MSG appears in exactly one place — MSH-9 — but that one place is the most important field in the entire message: it is what tells the receiver "this is an ADT, trigger A01, parse it as the ADT_A01 structure."
Purpose
MSG exists to give a receiver three pieces of information at once: what kind of message is this (Message Code), what real-world event triggered it (Trigger Event), and which exact structural template should the parser use (Message Structure). The third component is the one that engineers most often omit and most often need: many trigger events share a single structure (ADT_A01 covers A01 admit, A04 register-outpatient, A08 update-patient-information, and A13 cancel-discharge — all four trigger events are parsed using the same segment graph), and several pairs of trigger events that look related have different structures (ADT_A39 patient merge has a different structure from ADT_A01).
Without MSG.3, the receiver must maintain its own trigger-event-to-structure lookup table — and that table changes across HL7 versions. With MSG.3, the sender tells the receiver exactly which template to use, every time.
Component reference
Source: HAPI HL7v2 v2.8.1 javadocs — MSG. MSG has three components separated by ^. Length is not published in the javadocs (—).
| Seq | Name | Data Type | Length | Req | Table | Description |
|---|---|---|---|---|---|---|
| MSG.1 | Message Code | id | — | R | [HL70076] | Three-letter message code — ADT, ORU, ORM, SIU, MDM, DFT, MFN, BAR, RDE, RGV, RAS, OMG, etc. Identifies the category of message. |
| MSG.2 | Trigger Event | id | — | R | [HL70003] | Trigger-event code paired with the message code — A01, A04, A08, R01, O01, S12, T02, etc. Names the real-world event. |
| MSG.3 | Message Structure | id | — | R | [HL70354] | Structure ID — ADT_A01, ORU_R01, ORM_O01, SIU_S12, MDM_T02. Names the segment-grammar template the parser should apply. Required from v2.4 onwards. |
The composite is read together: MSG.1 + ^ + MSG.2 yields the conventional ADT^A01 display form; MSG.3 disambiguates structures when several trigger events share one.
Most-used components
- MSG.1 Message Code — the category. Routing engines first triage on this single value (ADT to the registration pipeline, ORU to results, ORM to orders, SIU to scheduling).
- MSG.2 Trigger Event — the event that produced the message. Within ADT,
A01admit andA03discharge fan out to different downstream consumers even though both share MSG.1=ADT. - MSG.3 Message Structure — the parser key. Tells the receiver which structure definition to use. Several trigger events share a structure (ADT_A01 covers A01, A04, A08, A13), so MSG.3 is not redundant with MSG.2 — it is strictly more specific in one direction and strictly less specific in the other.
Where it's used
MSG appears in exactly one field across all of HL7 v2:
- MSH-9 Message Type — the only field typed as MSG. Every conforming v2.4+ message carries one MSG in MSH-9, and that MSG is what gets logged, routed, acknowledged (via the matching MSA-2 control ID and MSA-1 acknowledgment code), and parsed.
That single placement is deceptive about its importance. MSH-9 is the second most-read field in any HL7 message after MSH-10 Message Control ID — every routing engine, audit log, replay tool, and conformance test reads MSH-9 to decide what the message is before reading anything else.
Version differences
- v2.1 / v2.2 / v2.3 / v2.3.1 — MSH-9 was a string field carrying
MessageCode^TriggerEvent(two components, no composite type). Some senders emitted a third component for structure; receivers parsed it positionally. - v2.4 — MSG composite introduced. MSH-9 retyped as MSG. Message Structure (MSG.3) became formally part of the type, although many senders continued to omit it during the v2.3→v2.4 transition.
- v2.5 / v2.5.1 — MSG.3 conformance tightened; HL7 table 0354 (Message Structure) curated as the canonical structure-ID list.
- v2.6 / v2.7 / v2.7.1 — No structural changes to MSG. New trigger events added to HL70003; new structure IDs added to HL70354.
- v2.8 / v2.8.1 / v2.8.2 — Structurally stable. HAPI v2.8.1 javadoc reflects the three-component layout unchanged.
Common mistakes
- Omitting MSG.3 Message Structure.
ADT^A01parses on lenient engines but is ambiguous on strict ones — and replay tools that hash on structure cannot index the message. Always emit the third component (ADT^A01^ADT_A01). - Mismatching MSG.2 and MSG.3. Sending
ADT^A08^ADT_A04is technically permissible (both A04 and A08 share the ADT_A01 structure in modern profiles), but most senders intendADT^A08^ADT_A01. The_A04form is almost always a copy-paste bug from a v2.3 template. - Inventing structure IDs.
ADT^A08^ADT_A08_v2orORU^R01^ORU_R01_LABare not in HL70354. Custom structures must be declared in a conformance profile, not invented in MSG.3. - Treating MSG.1 as case-insensitive. HL7 v2 IDs are case-sensitive in conformance contexts.
adt^a01^adt_a01will be rejected by strict parsers and silently miscategorized by lenient ones. - Underscore vs caret confusion. MSG.3 uses an underscore (
ADT_A01), not a caret (ADT^A01). The caret is the component delimiter inside MSG itself; using it inside MSG.3 produces a four-component MSG that does not parse. - Sending
ACKin MSG.2 instead of MSG.1. ACK is the message code for an acknowledgment; its trigger event is the trigger of the original message (e.g.ACK^A01^ACK). PuttingACKin MSG.2 produces a nonsense composite.
Examples
Minimal value (legal on v2.3-and-earlier emitters but discouraged):
ADT^A01
Conformant v2.4+ value with all three components:
ADT^A01^ADT_A01
Trigger events that share a structure:
ADT^A04^ADT_A01 ; register outpatient — same structure as A01
ADT^A08^ADT_A01 ; update patient info — same structure as A01
ADT^A13^ADT_A01 ; cancel discharge — same structure as A01
ADT^A39^ADT_A39 ; patient merge — distinct structure
Other common message types:
ORU^R01^ORU_R01 ; unsolicited observation result
ORM^O01^ORM_O01 ; order message (legacy)
OMG^O19^OMG_O19 ; general order (v2.5+)
SIU^S12^SIU_S12 ; new appointment
MDM^T02^MDM_T02 ; document notification with content
ACK^A01^ACK ; acknowledgment of an ADT^A01
In context — full MSH segment carrying an ADT^A08 update:
MSH|^~&|EMR|MERCY^2.16.840.1.113883.19.5^ISO|EHR|MERCY|20260624101530-0500||ADT^A08^ADT_A01|MSG-ADT-77321|P|2.8.1
EVN|A08|20260624101530-0500
PID|1||MR884412^^^MERCY&2.16.840.1.113883.19.5&ISO^MR||TESTPATIENT^ALEX^Q||19720508|F
PV1|1|I|3W^301^A^MERCY||||9988^Reyes^Marta^L^^^MD
In context — an unsolicited lab result:
MSH|^~&|LIS|MERCY^2.16.840.1.113883.19.5^ISO|EMR|MERCY|20260624110000-0500||ORU^R01^ORU_R01|MSG-LAB-44210|P|2.8.1
Common pitfall — MSG.3 omitted:
MSH|^~&|EMR|MERCY|EHR|MERCY|20260624101530-0500||ADT^A08|MSG-ADT-77321|P|2.8.1
ADT^A08 alone is parseable but ambiguous: the receiver must consult its own trigger-event-to-structure table to know that A08 uses ADT_A01. Strict v2.8.1 conformance profiles flag this.
Common pitfall — wrong structure paired with trigger:
MSH|^~&|EMR|MERCY|EHR|MERCY|20260624101530-0500||ADT^A39^ADT_A01|MSG-MRG-1|P|2.8.1
A39 (patient merge) does not use the ADT_A01 structure; it uses ADT_A39. The parser will read MRG and find segments out of expected order, then either reject the message or misroute the merge.
FHIR mapping
The HL7 v2-to-FHIR Implementation Guide publishes three ConceptMaps for MSG:
datatype-msg-to-coding— MSG.1 + MSG.2 combined into a singleCoding(systemhttp://terminology.hl7.org/CodeSystem/v2-0003, codeADT_A01-style).datatype-msg-to-messageheader— drives the surroundingMessageHeaderresource;MessageHeader.eventCodingis populated from the MSG composite.datatype-msg-to-code— for profiles that need only the bare event code as a string.
Component-level mapping:
| HL7 v2 | FHIR target |
|---|---|
| MSG.1 Message Code | embedded in MessageHeader.eventCoding.code (concatenated with MSG.2) |
| MSG.2 Trigger Event | embedded in MessageHeader.eventCoding.code |
| MSG.3 Message Structure | no direct equivalent — FHIR's resource graph is its own structure |
FHIR MessageHeader does not advertise message structure separately because the FHIR Bundle layout is the structure. Round-tripping HL7 → FHIR → HL7 requires the converter to re-derive MSG.3 from MSG.2 using a curated trigger-event-to-structure table, which is why most production converters carry one.
Engine considerations
- Routing key. Most engines route on MSG.1 alone, then fan out on MSG.2. Treating MSG.1+MSG.2 as a single tuple is more robust: ADT^A01 and ADT^A03 go to different destinations even though they share MSG.1.
- Structure validation. Strict profiles validate MSG.3 against HL70354 and against the actual segment graph parsed from the message. A claim of ADT_A01 followed by an MRG segment is internally inconsistent.
- Replay and idempotency. Replay tools should index messages by
(MSH-10 Message Control ID, MSG.1, MSG.2, MSG.3); using only MSH-10 is insufficient when senders reuse control IDs across message types. - Acknowledgment construction. ACK messages echo the original MSG with
ACKin MSG.1 and the original MSG.2 as the trigger — for example,ACK^A01^ACK. Some senders emitACK^^ACK, dropping MSG.2; modern profiles consider this non-conformant. - HAPI typing.
ca.uhn.hl7v2.model.v281.datatype.MSGexposes typed accessorsgetMessageCode(),getTriggerEvent(),getMessageStructure(). Each returns anIDinstance. Code that imports a different version's MSG class (e.g. v2.3 had no MSG type at all) will not compile against v2.8.1 structures. - Version mismatch with MSH-12. A v2.8.1 message that carries MSG.3=
ADT_A04(a structure ID that v2.7+ no longer publishes as canonical for A04) will load but should trigger a profile-version warning.
How Vorro parses and produces MSG
Vorro treats MSG as the primary routing key. On inbound, every message is parsed into (messageCode, triggerEvent, messageStructure) and the tuple drives the dispatch table — ADT^A01^ADT_A01 lands on the registration pipeline, ORU^R01^ORU_R01 on the results pipeline, SIU^S12^SIU_S12 on scheduling. When MSG.3 is missing, Vorro derives it from a curated trigger-event-to-structure table keyed off MSH-12 (the version identifier) and tags the message with provenance so the receiver can distinguish "structure asserted by sender" from "structure inferred at ingress."
When MSG.2 and MSG.3 disagree (e.g. A39 paired with ADT_A01), Vorro rejects the message at the edge rather than risk silent misrouting. On outbound, all three components are always emitted; Vorro never produces a two-component MSG even when the destination claims to be v2.3.
