Extracting Container and Weight Details From a Bill of Lading
10 min read · updated August 11, 2026
Most fields on a bill of lading can only be checked against another document. Two cannot: the container number verifies itself, and the weights verify each other. Building the extraction around those two properties gets you a validator that runs without a reviewer.
What the container number is made of
A freight container marking is defined by ISO 6346, and it is eleven characters in a fixed shape: three letters of owner code, one letter of equipment category, six digits of serial number, and one check digit. The owner code is registered — the Bureau International des Conteneurs maintains the register, and a prefix that is not in it is not a valid container number no matter what the arithmetic says. The fourth letter is the category identifier and takes one of three values: U for a freight container, J for detachable freight-container-related equipment, and Z for trailers and chassis. Anything else in that position is a misread.
ISO 6346 also defines the four-character size-and-type code that is stencilled below the number and often reprinted on the bill of lading in a separate column — 22G1 for a twenty-foot general purpose box, 45R1 for a forty-foot high-cube reefer. It is a different field with a different grammar, and it has no check digit. If your schema has one container_code field, these two end up fighting for it.
Computing the check digit
The check digit is a weighted sum modulo 11. Letters are mapped to numbers by a table that starts at 10 for A and skips every multiple of 11:
A=10 B=12 C=13 D=14 E=15 F=16 G=17 H=18 I=19 J=20 K=21 L=23 M=24 N=25 O=26 P=27 Q=28 R=29 S=30 T=31 U=32 V=34 W=35 X=36 Y=37 Z=38 (11, 22 and 33 are skipped, which is why L jumps from 21 to 23)
- Map the four letters to their values and keep the six digits as they are. That gives ten numbers.
- Multiply the number in position n by 2 raised to the power of n minus 1 — so the weights are 1, 2, 4, 8, 16, 32, 64, 128, 256, 512.
- Add the ten products.
- Take the remainder modulo 11. That is the check digit, except that a remainder of 10 is written as 0.
Worked on a synthetic number, TCLU1234568:
T=31 x 1 = 31
C=13 x 2 = 26
L=23 x 4 = 92
U=32 x 8 = 256
1 x 16 = 16
2 x 32 = 64
3 x 64 = 192
4 x 128 = 512
5 x 256 = 1280
6 x 512 = 3072
----
sum 5541
5541 = 11 x 503 + 8 -> check digit 8Ten lines of arithmetic and no model call. Run it on every container number the extraction returns and you have a hard signal that costs nothing, which is a different kind of evidence from a per-field confidence score and much better than one.
What the check digit does not catch
A passing check digit is evidence, not proof, and the size of the gap is calculable. Because the letter table skips multiples of 11, the twenty-six letters map onto only ten distinct residues modulo 11 — so letters collide in threes. B, L and V are all congruent to 1. C, M and W are all congruent to 2. A, K and U are all congruent to 10. Swap one member of a triple for another in the same position and the check digit is unchanged.
That is not theoretical. Take the owner code MSCU and change the first letter to C. M is 24 and C is 13; the difference is 11, multiplied by a weight of 1, so the sum falls by exactly 11 and the remainder does not move. Both MSCU1234566 and CSCU1234566 pass. The remedy is not more arithmetic, it is the owner register: check the three-letter prefix against the BIC list before you trust the digit.
There is a second, smaller hole. A remainder of 10 is written as 0, so check digit 0 is produced by two different remainders and is roughly twice as likely to be reached by accident as any other value. A container number ending in 0 that you cannot otherwise corroborate deserves marginally less trust than the other nine.
Three weights, one label
A bill of lading commonly prints something called “gross weight” and something called “net weight”, and a separate document or column carries a verified gross mass. These are three different quantities and an extraction that maps them to one field silently changes the number by a couple of tonnes.
- Net weight — the goods alone, without packaging in some usages and with it in others. It is the least standardised of the three.
- Gross weight — on a bill of lading, conventionally the cargo including its packaging and dunnage, but not the container itself.
- Verified gross mass — the figure required under the SOLAS convention, chapter VI, regulation 2, before a packed container may be loaded aboard a ship. VGM does include the container’s own tare.
That gives an arithmetic relationship you can check: VGM minus the container’s tare should approximate the cargo gross weight. The tare is stencilled on the container door alongside the maximum gross mass and the payload, so a manifest or equipment interchange receipt usually supplies it. A twenty-foot dry box tares somewhere near 2,200 kilograms; if VGM minus gross weight lands nowhere near a plausible tare, one of the two numbers was read from the wrong column.
The upper bound is useful too. The standard maximum gross mass marked on general-purpose twenty- and forty-foot ISO containers is 30,480 kilograms. Any extracted VGM above that is either a unit error or a decimal error, and both are common enough to be worth an explicit assertion rather than a reviewer’s eye.
Where the extraction actually breaks
The failures worth designing for are not the ones a schema catches.
- Units printed once, values printed many times. The column header says KGS and one line says LBS because that shipper always files in pounds. A value of 67,200 next to a value of 30,480 is the same weight twice, not an error.
- Separator ambiguity.
28.335is twenty-eight-point-three-three-five kilograms in one convention and 28,335 in another. Decide from the document’s other numbers, not from the locale of whoever is running the parse. - Character confusions that survive OCR. The digits and letters in a container number are adjacent in exactly the way OCR fails: 0 against O, 1 against I, 5 against S, 2 against Z. The check digit catches most of these, which is the argument for computing it rather than trusting a clean-looking OCR pass.
- Many containers, one bill. A single bill of lading frequently covers ten or twenty boxes, listed in a table that spills onto a continuation sheet with its own header. Extraction to a single object rather than a list is the most common structural mistake here.
- “Said to contain.” The carrier prints this to say the description and weights are the shipper’s declaration, not something the carrier verified. It does not change what you extract, but it does change what the extracted value means downstream, and it belongs in the record.