Printer troubleshooting technician providing live chat help

Joe B.

Reviewed for technical accuracy

Specialities: Thermal label printers, BarTender & NiceLabel, ZPL/EPL/TSPL, GS1-128, Code 128/39, SAP/WMS integrations

GS1 check digit not retained — Mod10/Luhn, Code 39 Mod43, template field mapping, printer-side serialization

Technician avatar Technician
Hey! We’ll figure out why the serialized parts label does not retain the check digit and make it stick for every print.
Quick context questions so I target the fix: which symbology are you using — GS1-128 (AI 01/21), plain Code 128, or Code 39 Mod43? Is the serial generated in your WMS/SAP or by the printer template (ZPL ^SN / ^FN)? And are you designing with BarTender or NiceLabel, or sending raw ZPL from a web app?
Customer
We print GS1-128. The data is (01)GTIN and (21)serial. The first label calculates the Mod10 check digit correctly for the GTIN, but when the serial increments the next labels sometimes drop or repeat the check digit. We design in BarTender; ZPL goes to Zebra ZT230.
Technician avatar Technician
Understood. Common causes when a GS1 check digit is not retained:
• The check digit is computed in the software layer but the template maps the base number (without the digit) to the barcode object.
• Printer-side serialization (^SN or variable counters) increments the wrong field, causing the Luhn/Mod10 value to be stale.
• Concatenation with FNC1 or AI formatting is off, so the driver strips the last character as a separator.
• In BarTender/NiceLabel the “Calculate check digit” box is only applied at preview, not to live data import from your WMS.
We’ll align the data source, ensure the check digit formula runs on each print, and lock it into the barcode output.
Customer
The GTIN comes from our database without the digit; BarTender is set to “Calculate Mod10”. Serialization is on the (21) field. After 5–6 labels the scanner says “invalid check digit”.
Technician avatar Technician
Step 1 — Force check digit on the data you actually print
• In BarTender, open the GS1-128 object → Data Sources. For AI (01) choose “Compute check digit” and ensure the output variable is the computed string, not the base GTIN field.
• If you use a database field like GTIN_Base, create a new transform: Mod10 (Luhn) and bind the barcode to GTIN_WithCD.
• Verify that Application Identifier formatting is enabled and FNC1 is automatic after (01) when additional AIs follow. This prevents the last character being treated as a separator instead of a digit.
Customer
That helps for GTIN. But our issue appears when the (21) serial increments — the printed text shows the new serial, yet the barcode content seems to reuse the previous frame’s last character.
Technician avatar Technician
That’s a classic template field mapping mismatch. In ZPL, confirm the same data source feeds both human-readable text and barcode fields:
• Use ^FN1 for the serial variable, then reference ^FN1 inside the barcode object. If the barcode uses hardcoded ^FD from a previous job, it won’t refresh.
• If you’re using ^SN (printer-side serialization), keep it on the (21) serial only and do not include the check digit there — GS1 check digits apply to (01) GTIN, not to (21).
• Make sure the print width/field length (^FB/^FT) isn’t truncating the final character.
Customer
We also print a Code 39 version for legacy parts. It’s supposed to use Mod43. Sometimes the human-readable includes the checksum but the barcode doesn’t.
Technician avatar Technician
For Code 39 Mod43 ensure “Include check digit in symbol” is enabled on the barcode object, not just appended as text. Otherwise the printed characters show the checksum while the symbol encodes only the base data.
For Code 128 (non-GS1), use the app’s built-in check digit option or compute it in a field script so the digit is part of the encoded data stream. Consistency between human-readable and encoded is key for verification.
Customer
We send jobs via a web service that merges variables. Could caching be why the check digit doesn’t update between prints?
Technician avatar Technician
Yes. Middleware sometimes reuses the prior ZPL frame. Best practices:
• Send a fresh ZPL header each job: ^XA^JUS^MTT^PMN and explicitly define variables (^FN) before fields that consume them.
• If BarTender/NiceLabel prints to a “Printer Code Template”, disable spooling optimizations that combine jobs, and pass serials as data sources with checksum computed post-merge.
• For SAP/WMS, confirm the modulo calculation runs server-side on every request and isn’t cached with the previous serial.
Customer
We verify with a handheld scanner. When it fails, it says “invalid check digit” or reads the GTIN without the last digit. Could FNC1 be the culprit?
Technician avatar Technician
Very possible. In GS1-128, (01) is fixed length; (21) is variable length and must be FNC1-terminated unless it’s the last element. If your template inserts FNC1 incorrectly, some scanners interpret the last character as the separator and drop the check digit from the GTIN.
• In BarTender/NiceLabel, enable “Use GS1 Application Identifiers”.
• In ZPL, use ^BCN,100,Y,N,N with ^FD>8 (switch to Code Set C) and include \^1 where FNC1 is required. Ensure (01) is 14 digits (including check digit) and (21) follows without truncation.
Customer
Okay, after mapping the computed GTIN and fixing FNC1, the scan passes. Can we lock this so future edits don’t break the check digit again?
Technician avatar Technician
Final hardening:
• Store GTIN_Base (without digit) in the DB and generate GTIN_WithCD via a formula/transform that’s part of the label file under version control.
• Disable printer-side serialization for GTIN; keep it for the (21) serial only.
• Add a post-print verify step: your handheld should validate Mod10 and AI structure. Save failed scans for audit.
Need help standardizing templates across sites (Zebra, TSC, Honeywell)? Open the chat — we’ll tune BarTender/NiceLabel and ZPL.
Customer
Perfect — labels now retain the check digit and our scanners validate every print. Thanks!
Technician avatar Technician
Summary: When a serialized parts label does not retain the check digit, compute the digit on the output field, align template mapping for both text and barcode, fix GS1 FNC1 placement, and avoid printer-side increments on GTIN. This keeps Mod10/Mod43 consistent across prints. Want help auditing your templates? Open the chat.

Quick answer: the accepted fix

Accepted fix when serialized parts labels don’t retain the check digit: compute the digit (GS1 Mod10/Luhn or Code 39 Mod43) on the final encoded field, bind the barcode to that computed value, ensure correct FNC1/AI formatting, and keep printer-side serialization only on the (21) serial. This prevents stale or missing digits.


Why check digits disappear — GS1 AI formatting, Luhn math, printer templates

The check digit can drop when the driver encodes the base GTIN instead of the computed value, when FNC1 is placed incorrectly between AIs, or when ZPL templates reuse ^FD data from a previous job. Make sure the Mod10 (Luhn) or Mod43 calculation runs for each print, and that the barcode and human-readable fields share the same data source.

How to verify check digit retention

Print three labels in a row. Scan with a verifier or handheld set to GS1-128. Confirm (01) contains 14 digits (including the Mod10 digit) and (21) serial changes each label. For legacy Code 39 Mod43, compare the printed checksum to the encoded symbol. If mismatched, review template mapping and enable “include check digit in symbol.”

Check digit retention — quick troubleshooting tips

Most failures trace to field mapping or GS1 formatting, not the scanner.

Quick path: compute check digit on output → bind barcode to computed field → verify FNC1 after variable AIs → avoid ^SN on GTIN → turn off caching/combined jobs in middleware. Works across Zebra, TSC, Honeywell, SATO with BarTender or NiceLabel.

Disclaimer: This information is AI-generated and intended for general guidance only. For advice specific to your environment, please consult a verified expert on Whizz-Tech before making decisions.


Getting Started Is Easy

Ask for help, 24/7

Members enjoy round-the-clock access to 12,000+ verified Experts, including tech support, mechanics, vets, and more.

Expert will respond in minutes

We match you with an Expert who specializes in your situation. Talk, text, or chat — whichever you prefer.

Save time & money

No scheduling hassles or expensive consults. Membership can save you significant time and money each month.

FAQ

Why doesn’t my serialized label keep the GS1 check digit?

The barcode object often uses the base GTIN field while the check digit is computed elsewhere. Map the barcode to the computed output, not the raw field, and ensure FNC1 is placed correctly.

Do I compute Mod10 for (21) serials?

No. GS1 Mod10 applies to identifiers like (01) GTIN. The (21) serial is variable length and usually has no check digit; just ensure it’s not truncating and is FNC1-separated when followed by another AI.

How do I handle Code 39 Mod43 and Code 128?

Enable “include check digit in symbol” for Code 39 Mod43. For Code 128, compute and append the checksum in the same data source used by the barcode, not only in the text line.

Printer template vs software — which should serialize?

Keep software-side Mod10 and AI formatting. Use printer-side ^SN only for the (21) serial. Avoid mixing sources to prevent stale digits and caching issues.

Common check digit problems and quick fixes
SymptomLikely causeQuick fix
Scanner says “invalid check digit” Barcode encodes base GTIN without digit Bind to computed Mod10 field; enable GS1 AI formatting
First label OK, next labels fail Cached ZPL / stale ^FD Send fresh variables (^FN), disable job combining, reset header
Human-readable shows digit, symbol doesn’t Text uses formula, barcode uses raw field Map both text and barcode to the same computed source
Legacy Code 39 fails verification Mod43 only in text Enable “include check digit in symbol”

Step-by-step (BarTender/NiceLabel + ZPL)

  1. Compute Mod10 (Luhn) on the GTIN field and bind the barcode to the computed output.
  2. Use proper GS1 AIs with FNC1 where required; ensure (01) is 14 digits including the check digit.
  3. Serialize only the (21) serial (software or ^SN), not the GTIN. Keep both text and barcode tied to the same variables.
  4. Prevent caching: send fresh ZPL variables with ^FN, avoid template reuse that retains old ^FD content, and verify three consecutive labels with a scanner.

Notes for mixed environments (drivers & printers)

  1. Use Zebra/Honeywell/TSC drivers that support GS1-128 formatting; don’t print as plain Code 128.
  2. If sending raw ZPL from macOS or Linux, build the string server-side with the computed check digit before transmit.

Sources

Matt Verified Icon
Matt ● replies in < 1 min
Technician Expert
⭐⭐⭐⭐⭐ Trusted by 27,000+ customers
Avatar
Alex · Expert's Assistant