Reject bad HL7 before it becomes a ticket

Interface engines fail in boring, expensive ways: a partner sends a message with an empty MSH-10, or an ORU with no patient segment. Downstream billing and EMR posts then fail an hour later. Catching that at the edge — with a stable error code — is the job.

HL7 v2 parse, validate, and structured error path

hl7-toolkit is a small HL7 v2 parser and validator. It turns a pipe-delimited message into JSON and rejects messages that would fail a healthcare interface: missing MSH, missing control ID, ADT/ORU without PID.

This is the public version of work I do on healthcare file and interface traffic. No PHI. Fake names and MRNs only. The file transfer pipeline uses a fast MSH gate; this repo is the deeper check that explains why a message is bad.

Parse, then decide

The flow is intentionally short:

  1. Read a raw HL7 v2 file.
  2. Split it into segments.
  3. Validate MSH (and PID when the message type requires a patient).
  4. Emit JSON on success, or a structured error with a field path on failure.

A failure should look like an API, not a stack trace

When a control ID is missing you cannot ack or dedupe. The toolkit says that in JSON, with a code you can log, alert on, and show a partner:

hl7kit validate tests/fixtures/missing_control_id.hl7
{
  "ok": false,
  "error": {
    "code": "MSH_10_MISSING",
    "message": "MSH-10 control ID is required",
    "path": "MSH-10"
  }
}

Rules that earn their keep

Code When
EMPTY_MESSAGE File has no content
NO_MSH First segment is not MSH
MSH_9_MISSING No message type
MSH_10_MISSING No control ID — you cannot ack or dedupe
MSH_12_MISSING No version
PID_MISSING ADT / ORU / ORM without a patient segment

Run it

python3 -m venv .venv
source .venv/bin/activate
pip install -e ".[dev]"
hl7kit validate tests/fixtures/adt_a01.hl7
hl7kit parse tests/fixtures/adt_a01.hl7
pytest -q

Why a toolkit instead of a one-off script

Healthcare interfaces accumulate special cases until nobody wants to touch them. A small CLI with pytest fixtures and stable error codes is easier to talk about in an interview and easier to extend when the next partner sends an ORM without PID. Pair it with the pipeline post if you want the landing-zone half of the same story.

GitHub repo File transfer pipeline post Back to projects