Error code reference¶
When pyx12 validates an X12 document, every problem it finds is recorded against the document tree at one of five levels (interchange, functional group, transaction set, segment, or element).
pyx12 4.1.0 introduced an internal pyx12 error code namespace
(ELE_6_invalid_composite, SEG_3_too_many_elements, …) backed by
a central registry in pyx12.error_codes. Producers (validators,
walker, parser) emit pyx12 codes; visitors translate to the X12-spec
AK3 / AK4 / AK5 / AK9 / TA1 “note codes” at output time. The pyx12
codes appear in:
the
err_cdefield onpyx12.error_item.EleError/pyx12.error_item.SegError,the
err_cdefield on entries inpyx12.error_handler.errh_list/ theerr_handlertree,the
err_cdefield on each error in JSON output, paired with anx12_codefield carrying the dereferenced X12 code.
The X12 numeric codes (“1”, “8”, etc.) appear only in the 997 / 999
acknowledgement output and the JSON x12_code field — visitors look
them up via pyx12.error_codes.ERROR_CODES.
This page documents every pyx12 code, what each one means, and the X12 code each maps to. It also documents the X12 spec codes that surface at envelope levels (ISA / GS / ST) which are not yet migrated to pyx12 codes.
How errors are surfaced¶
The top-level validator (x12valid / pyx12.x12n_document.x12n_document())
returns False when any error fires, writes a 997 / 999 acknowledgement,
and logs the human-readable message. x12n_document constructs its own
internal error handler and renders results into the 997 / 999 / HTML output
files; for programmatic access to individual errors, drop one level lower to
pyx12.x12file.X12Reader or pyx12.x12context.X12ContextReader
and supply your own handler. errh_list collects errors into per-level
lists you can iterate directly.
The five levels:
Level |
Pyx12 method |
997 / 999 segment |
|---|---|---|
Interchange (ISA) |
|
TA1 (interchange ack) |
Functional Group |
|
AK9 |
Transaction Set |
|
AK5 / IK5 |
Segment |
|
AK3 / IK3 |
Element / sub-ele |
|
AK4 / IK4 |
Pyx12 error codes¶
Code names follow the convention <LEVEL>_<X12_CODE>_<descriptor>:
LEVEL is one of
ELE,COMP,SEGindicating where the error attaches in the err_handler tree (composites surface as element-level errors in IK4 / AK4 output).X12_CODE is the AK4 / IK4 / AK3 / IK3 code the visitor will emit for this error in the 997 / 999 ack.
descriptor is a short snake-case discriminator. Multiple pyx12 codes can map to the same X12 code (e.g. four element-level checks all map to AK/IK
"6"); the descriptor distinguishes them on the CLI and in JSON output.
Element-level pyx12 codes¶
Raised by pyx12.map_if.element_if when validating a single
element value against its map definition.
pyx12 code |
AK4 |
IK4 |
Meaning |
|---|---|---|---|
|
1 |
1 |
Mandatory data element missing |
|
4 |
4 |
Data element shorter than |
|
5 |
5 |
Data element longer than |
|
6 |
6 |
Composite element used at non-composite position |
|
6 |
6 |
Trailing space in data element |
|
6 |
6 |
Control character in data element |
|
6 |
6 |
Invalid character for declared element data type |
|
7 |
7 |
Data element does not match required regex pattern |
|
7 |
7 |
Data element value not in valid code list |
|
8 |
8 |
Invalid date (declared D8/D6/DT/RD8 type) |
|
8 |
8 |
Invalid date in multi-type validation |
|
9 |
9 |
Invalid time (declared TM type) |
|
9 |
9 |
Invalid time-of-day in multi-type validation |
|
— |
I10 |
Data element marked Not Used (usage=’N’) but populated |
Composite-level pyx12 codes¶
Raised by pyx12.map_if.composite_if when validating a
composite element. Surface as element-level errors in IK4 / AK4 output.
pyx12 code |
AK4 |
IK4 |
Meaning |
|---|---|---|---|
|
1 |
1 |
Mandatory composite element missing |
|
3 |
3 |
Composite has too many sub-elements |
|
5 |
5 |
Composite marked Not Used (usage=’N’) but populated |
Segment-level pyx12 codes¶
Raised by pyx12.map_if.segment_if (validator), pyx12.map_walker
(walker), and pyx12.x12file (parser).
pyx12 code |
AK3 |
IK3 |
Meaning |
|---|---|---|---|
|
3 |
3 |
Segment has too many elements (validator) |
|
3 |
3 |
Segment has too many sub-elements in a composite (validator) |
|
2 |
2 |
Segment syntax rule (relational) violated |
|
10 |
10 |
Segment syntax rule (exclusive) violated |
|
1 |
1 |
Unrecognized segment ID (walker) |
|
2 |
2 |
Segment marked Not Used (usage=’N’) |
|
2 |
2 |
Loop marked Not Used (usage=’N’) |
|
3 |
3 |
Mandatory segment missing |
|
3 |
3 |
Mandatory loop missing |
|
4 |
4 |
Loop repeat count exceeded |
|
5 |
5 |
Segment repeat count exceeded |
|
1 |
1 |
Segment identifier malformed (parser) |
|
1 |
1 |
Segment line started with leading whitespace |
|
8 |
8 |
Segment is empty (parser) |
|
8 |
8 |
Segment has trailing element terminators |
|
— |
— |
|
|
— |
— |
|
|
— |
— |
837 |
A dash (”—”) in the AK3/IK3 column means the code is preserved in the err_handler tree and JSON output but suppressed from the X12 ack (historical behavior preserved across the 4.1.0 refactor).
The seg-level validator codes (SEG_3_too_many_elements,
SEG_3_too_many_subelements, SEG_2_syntax_relational,
SEG_10_syntax_exclusive) plus the composite-level codes flow
through the bridge in pyx12.map_if._segment.apply_segment_errors(),
which routes seg-level errors via errh.seg_error with a hardcoded
"8" code (X12 spec correctness); the original AK3/IK3 column above
is the canonical mapping for the pyx12 code itself, but the actual ack
output for these specific codes will show "8" instead. See
pyx12.map_if._segment.apply_segment_errors() for the routing logic.
Source: see pyx12.error_codes.ErrorCodeSpec and
pyx12.error_codes.ERROR_CODES.
Transaction-set codes (AK5 / IK5)¶
Raised when validating ST/SE envelope structure.
Code |
Meaning |
|---|---|
|
Mandatory |
|
|
|
|
|
|
Functional-group codes (AK9)¶
Raised when validating GS/GE envelope structure.
Code |
Meaning |
|---|---|
|
Unterminated GS loop / mandatory |
|
|
|
|
|
|
Interchange codes (TA1)¶
Raised when validating ISA/IEA envelope structure. These three-digit codes
match the values defined for the TA105 element of a TA1 interchange
acknowledgement.
Code |
Meaning |
|---|---|
|
|
|
|
|
Mandatory |
|
Unterminated GS loop within the interchange |
|
|
Source: X12Reader._parse_segment and X12Reader.cleanup in
pyx12.x12file.
Worked example: SEG_5_segment_repeat_exceeded¶
Suppose x12valid produces this output against an 837P:
ERROR: Segment NM1 exceeded max count. Found 2, should have 1
(line 142, code='SEG_5_segment_repeat_exceeded', x12_code='5')
This is a segment-level error (the SEG_ prefix). Looking it up
in the segment-level table above tells you the loop is allowing the
NM1 to appear more times than the implementation guide permits —
typically a sign that two distinct loop instances have been collapsed
into one because of a missing loop-anchor segment between them.
To debug:
Open the input at line 142.
Walk backwards to the previous loop-anchor segment (often
HLorCLM).Check whether a required separator segment (
CLM,LX,HL, …) is missing — that is usually why the second occurrence ofNM1is being attached to the previous loop instead of starting a new one.
The 999 ack for this error will emit IK3*NM1*<seg_count>**5~ (the
5 is from the table’s IK3 column; x12_code in JSON output
matches it).
Reading errors from Python¶
For programmatic access, validate via pyx12.x12context.X12ContextReader
with an pyx12.error_handler.errh_list so each level’s errors land in
plain lists you can iterate. Segment- and element-level codes are pyx12
codes (SEG_* / ELE_* / COMP_*); ISA / GS / ST envelope codes
are still raw X12 strings.
import pyx12.error_handler
import pyx12.params
import pyx12.x12context
param = pyx12.params.params()
errh = pyx12.error_handler.errh_list()
with open("claim.x12", "rb") as fd_in:
src = pyx12.x12context.X12ContextReader(param, errh, fd_in)
for _ in src.iter_segments():
pass # walking the document populates errh
for code, msg in errh.err_isa:
print(f"ISA {code}: {msg}") # raw X12 codes ("025", "010", ...)
for code, msg in errh.err_gs:
print(f"GS {code}: {msg}") # raw X12 codes
for code, msg in errh.err_st:
print(f"ST {code}: {msg}") # raw X12 codes
for code, msg, value in errh.err_seg:
print(f"SEG {code}: {msg}") # pyx12 codes ("SEG_3_*", ...)
for code, msg, value, ref_des in errh.err_ele:
print(f"ELE {code} ({ref_des}): {msg}") # pyx12 codes ("ELE_8_*", ...)
For the tree-shaped handler that the 997 / 999 generators consume, use
pyx12.error_handler.err_handler and walk it with the
pyx12.error_visitor.error_visitor protocol — see
pyx12.error_debug.error_debug_visitor for a worked example.
To resolve a pyx12 code to its X12 ack code in your own code, look it up in the registry:
from pyx12.error_codes import ERROR_CODES, x12_code_for
spec = ERROR_CODES["ELE_8_invalid_date"]
spec.ak_code # "8" (4010 ack)
spec.ik_code # "8" (5010 ack)
spec.level # "ELE"
spec.description # "Data element contains an invalid date (D8/D6/DT)"
# `x12_code_for` is the helper used by the JSON visitor's `x12_code`
# field: returns spec.ik_code (preferred) or spec.ak_code, or the
# err_cde itself for codes not in ERROR_CODES (envelope-level codes).
x12_code_for("ELE_8_invalid_date") # -> "8"
x12_code_for("025") # -> "025" (ISA-level passthrough)
Suppressing codes¶
Pyx12 codes can be filtered out before they reach the err_handler tree. Suppressed errors do not appear in the 997/999 ack, the JSON output, or any error-count tally. The validator’s overall verdict (valid/invalid) is unaffected by suppression — pyx12 still knows the segment had errors, it just doesn’t surface them to consumers.
CLI:
x12valid -J --suppress ELE_6_invalid_composite,SEG_3_too_many_elements -- input.x12
The flag is comma-separated; you can also repeat -S / --suppress
to add codes:
x12valid -S ELE_6_invalid_composite -S SEG_3_too_many_elements -- input.x12
Programmatically:
import pyx12.params
import pyx12.x12n_document
param = pyx12.params.params()
param.set("suppress_error_codes", {"ELE_6_invalid_composite"})
with open("input.x12") as fd, open("output.997", "w") as fd_997:
pyx12.x12n_document.x12n_document(param, fd, fd_997, None, None)
Suppression operates on pyx12 codes, not the underlying X12 codes:
suppressing ELE_6_invalid_composite filters only the composite-mistake
emission, not the three other element-level checks that also map to AK4
"6" (control character, trailing space, invalid type character).
This is the granular control the pyx12 code namespace was introduced to
provide.