Blog
Walmart's Own X12 Library Says a Clean Parse Is Not a Valid Message. The CTT Is Your Free Proof
A cleanly parsed 856 is a transport fact, not a valid message, and the CTT count inside the file is a check nobody can refuse.
Your 856 parsed. The integration reported success, the transaction set loaded, and the ASN charge landed anyway.
That combination is not a bug in your parser. It is the design.
The most authoritative statement of it in EDI does not come from a vendor selling
you a validation layer. It comes from the retailer's own open-source X12
library, gozer, published by Walmart Labs: "If the EDI message was well-formed
and successfully parsed that does not mean that it is valid. The parsers,
intentionally, do not attempt to validate any values within the segment elements
(other than segment identifiers)."
It is named for a Ghostbusters character, which is the least authoritative thing about it, and it is why you can say "we parsed it" and know the sentence does not help.
The same rule applies to our own parser, and it would be poor form to write this post otherwise. Our 856 reader either becomes a row keyed to a purchase order or it stops, and the checks it runs are Walmart's three. A successful parse is a transport fact. Validity is somebody else's job, and the job has no default owner.
What a successful parse actually certifies
Gozer's design note is precise about the three, and it is the contract you are really operating under.
| A clean parse proves | A clean parse does not prove |
|---|---|
| The segments carry the correct segment identifiers | That any value inside a segment is right |
| The segments are nested correctly | That the loop shape is the one the partner expects |
| The segments appear in the proper order | That the file is the whole file |
If the message is not well-formed the parser throws; everything past that is a judgement, and the library hands the judgement to you. "Properly ordered" is a claim about order, not about completeness.
The free check nobody runs: the CTT
The 856 carries a segment called CTT, the transaction totals segment, which
carries counts a receiver can check the transaction set against. In gozer's own
856 test file the last two lines of the transaction set are CTT*4*30 and
SE*31*0008.
Read them the way the sender meant them. The first number is 4, and the file contains exactly four hierarchy segments: one shipment, one order, two items. The second is 30, and the closing segment declares 31, the same thirty, with the closing segment itself counted in. The counts agree. That is what agreement looks like, and it is the part you can check without asking anyone for anything.
When they disagree, the arithmetic is a standalone fact. A file that declares thirty segments and holds twenty-nine is short of what it claims, and the sender's own hash total is the evidence, no log export, no call into their EDI team, no TA1, no 997, no meeting. The proof sits in the file you already sent, and it is the only proof in this post that needs nobody else's cooperation.
The check is one afternoon: count the segments, compare against what the file declares, alert on a difference. Calibrate it once per trading partner, because exactly which segments the number covers comes from that partner's implementation guide and not from the standard, a point this post returns to at the end.
The other free check: the loop shape
An 856 nests in a predictable order, and gozer documents it plainly: a shipment loop, an order loop under it, then a pack or a tare loop, then item loops, with the container identifier on a mark-and-number segment in the pack loop carrying the serial shipping container code or the bill of lading. Those letters are the shape, and the shape is checkable without a partner. The retailer's receiving system has to match that file to the load, and what the 856 gets checked against is the physical trailer.
What release 0.3.0 changed, and why it is the dangerous part
Gozer used to throw. Earlier versions stopped the parse dead with an exception on a looping error. From release 0.3.0 it does not:
"Invalid looping is now treated as a post-parsing validation error. It will be up to the user of the framework to check the value."
That release moved the 824 with it. The design note recommends users build their own validation so they can "decide how best to handle the generation of 824 warnings and errors when validation fails." Generating the warning is a caller responsibility too.
Now notice what the same document already said: a successful parse requires segments that "be nested correctly," and an error in looping no longer stops the parse. Those two statements do not sit together cleanly and the documentation does not resolve them. The safe reading is the second: assume a bad loop came through, because the exception that used to tell you it did is gone.
Set that beside the first quote and the failure mode is complete: a structural error that once produced an exception and a ticket now returns a value on the parsed object. A file that would once have failed loudly can pass, be logged as delivered, and be wrong for the life of the account.
And the person who has to prove it six weeks later has nothing. The framework never recorded what should have happened, so the log shows a clean parse, the dashboard a shipped ASN, and the deduction arrives against a file that is defensible and empty. The 824 is the message that would have said so, and if nothing in your stack reads the attribute, you never get one.
Four things, and none of them is a project
Log the expectation next to the parse. When you write a transaction set, write the counts you declared and the counts you built. A log recording only the fact of success cannot answer a question six weeks later. The expectation is the only half that was ever in dispute.
Keep the raw bytes. The file you sent is the only artefact that can be re-checked. If the transmission log holds a timestamp and not the document, the arithmetic is gone retrospectively and the check only worked on the day it was written.
Make a mismatch an alert, not a metric. A CTT difference is a binary event, not a trend. Route it to whoever can fix the mapping, the same day, the way the 997 and the 824 are documents rather than a report.
Write down the convention per partner. Which segments the count covers, what a valid loop shape is for that retailer, which value in which segment has to match your item master. None of it is public. Write it down or the next engineer inherits the parse log and none of the context.
What this post is not
Gozer is one implementation, and it is Walmart Labs' parsing library rather than Walmart Retail's inbound specification. Nothing in it tells you what any given retailer's 856 is required to contain, and reading its README as a requirements document is precisely the confusion this post is about.
The counting convention is the sharpest gap. The standard's CTT definition is
general: a hash total of a specified element, and what the number means comes
from the trading partner's guide. Walmart's EDI mapping guide sits behind a Retail
Link login. So the fixture above demonstrates arithmetic and nothing more: it is
a test file in a library repository, written against a 004060 group header, not
a production transmission from a distribution centre.
Nobody publishes how often real 856s fail these checks, and no retailer publishes a pass rate. The rates you can act on are the ones you measured last quarter.
Three signals in this post are computable from a file already in your hands: the counts it declares, the shape of its loops, and the number of hierarchy segments inside them. Our compiled portal reference puts Walmart's ASN and labelling penalties at $50 to $500 per incident, and the clock on that deduction runs about 30 days from the invoice. The CTT takes one afternoon to wire in, and it is the only proof here that does not need the retailer to agree with you.
Keep reading
- The ASN Is Valid, the Shipment Is Wrong, and You Get Charged
The 856 ship notice is checked against what physically arrives, so a file that validates cleanly is not the same as a file that is correct.
- Walmart Reverses ASN Fines on the 997. Almost Nobody Keeps One.
The 997 is the cheapest document in EDI, almost nobody archives it, and it is the evidence Walmart says reverses ASN fines.
- The 824 Tells You Your ASN Was Rejected. Almost Nobody Reads It
The 997 says your file arrived. The 824 says whether it survived validation. Most teams read the first and miss the second.
Want to know what you're owed right now?
Join the waitlist for early access to Disputek.
Join the waitlist →