Error Handling¶
hl7types provides errs_from_exception, a helper that converts a Pydantic
ValidationError into a list of fully spec-compliant ERR segments ready to be embedded in
a negative acknowledgement. It handles the structural differences between HL7 versions
automatically, so the correct ERR form is produced regardless of whether you are working with
v2.1 or v2.8.2. We fawn over good error handling here.
Any time a Pydantic ValidationError is raised, whether from decode_er7, direct model
construction, or model_validate, errs_from_exception converts it into a list of ERR
segment instances, one per violated field, using the correct ERR structure for the HL7
version in use. Those segments can then be placed directly into a negative acknowledgement and
returned to the sender. Don’t get caught deer in the headlights when validation fails we’ve
got you covered, no ifs, ands, or bucks.
from hl7types import decode_er7, HL7Registry
from hl7types.utils.error import errs_from_exception
from hl7types.hl7.v2_8_2.messages import ACK
from hl7types.hl7.v2_8_2.segments import MSA, MSH
from hl7types.hl7.v2_8_2.datatypes import HD, MSG, PT, TS, VID
try:
decode_er7(wire, registry=registry, strict=True)
except Exception as e:
errs = errs_from_exception(e, "2.8.2")
msh = MSH(
msh_3=HD(hd_1="RECEIVING_APP"),
msh_5=HD(hd_1="SENDING_APP"),
msh_7=TS(ts_1="20260101120000"),
msh_9=MSG(msg_1="ACK"),
msh_10="MSG000002",
msh_11=PT(pt_1="P"),
msh_12=VID(vid_1="2.8.2"),
)
msa = MSA(msa_1="AE", msa_2="MSG000001")
nak = ACK(MSH=msh, MSA=msa, ERR=errs)
print(nak.model_dump_er7())
Output:
MSH|^~\&|RECEIVING_APP||SENDING_APP||20260101120000||ACK|MSG000002|P|2.8.2
MSA|AE|MSG000001
ERR||PID^1^3|101^Required field missing^HL70357|E
ERR||PID^1^8|103^Table value not found^HL70357|E
Each ERR segment identifies the offending segment and field position (ERR.2), carries a
structured HL7 error code from table HL70357 (ERR.3), and sets severity to E for error
(ERR.4). MSA.1 is set to AE (application error) to signal to the sender that the
message was rejected. Quite the reindeer of errors, all neatly lined up.
If the exception is not a ValidationError, errs_from_exception returns an empty list. It
is the caller’s responsibility to handle other exception types independently. No need to go
stag-gering around looking for errors that aren’t thereif the list is empty, you’re in the
clear. Deerly noted.
Error codes¶
Error codes are drawn from HL7 table 0357. The following codes are generated automatically from Pydantic validation errors. The bucks stop here:
Code |
Description |
Triggered by |
|---|---|---|
|
Required field missing |
A required field was absent from the message |
|
Data type error |
A field value did not match the expected HL7 datatype |
|
Table value not found |
A coded field contained a value not present in the referenced table |
|
Value too long |
A field value exceeded the maximum defined length |
|
Other HL7 Error |
Any validation error not covered by the above categories |
Version differences¶
The structure of the ERR segment changed significantly across HL7 versions.
errs_from_exception produces the correct form automatically based on the version string
passed to it. It’s a doe or die situation, and we handle every version without missing a
single hart-beat.
v2.1 and v2.2: ERR.1 is a repeating CM field carrying the error code and location as a
single composite string. Fawn-damentally simple:
errs = errs_from_exception(e, "2.1")
# ERR|101~PID.3
v2.3 and v2.3.1: ERR.1 is a repeating ELD (error location and description)
datatype. The error code is carried in ELD.4 as a CE coded element referencing
table HL70060. Things are getting a little more stag-gered:
errs = errs_from_exception(e, "2.3")
# ERR|PID^1^3^101&Required field missing&HL70060
v2.4 and later: ERR carries a fully structured response. The error code appears in
ERR.3 as a CWE referencing table HL70357, the field location in ERR.2 as an ERL,
and the severity in ERR.4. Elk-egant:
errs = errs_from_exception(e, "2.8.2")
# ERR||PID^1^3|101^Required field missing^HL70357|E