How to Validate Barcode Checksums and Use Format-Aware Reading in C#
Barcode checksums help detect substitution errors. For example, a single transposed digit in an EAN-13 label can send a package to the wrong warehouse. Format-aware reading provides an additional validation layer by restricting the decoder to expected symbologies. This approach reduces false positives from background noise and shortens scan time by skipping unnecessary format detectors.
IronBarcode performs checksum verification automatically during decoding. Each symbology's check-digit algorithm runs by default, and barcodes that fail are discarded before results are returned. The BarcodeReaderOptions.ExpectBarcodeTypes property limits reads to specific formats, while RemoveFalsePositive adds a secondary scan for ambiguous reads.
This guide explains how to validate barcode checksums, constrain reads to expected formats, and combine both techniques into a layered quality gate using BarcodeReaderOptions.
Configure BarcodeReaderOptions with ExpectBarcodeTypes and RemoveFalsePositive to constrain reads to expected symbologies with automatic checksum verification.
using IronBarCode;
// Format-constrained read with false-positive removal.
// Limit the decoder to EAN-13 and Code128; checksums are
// validated automatically and failures are silently discarded.
var options = new BarcodeReaderOptions
{
ExpectBarcodeTypes = BarcodeEncoding.EAN13 | BarcodeEncoding.Code128,
RemoveFalsePositive = true,
Speed = ReadingSpeed.Balanced
};
BarcodeResults results = BarcodeReader.Read("label.png", options);Imports IronBarCode
' Format-constrained read with false-positive removal.
' Limit the decoder to EAN-13 and Code128; checksums are
' validated automatically and failures are silently discarded.
Dim options As New BarcodeReaderOptions With {
.ExpectBarcodeTypes = BarcodeEncoding.EAN13 Or BarcodeEncoding.Code128,
.RemoveFalsePositive = True,
.Speed = ReadingSpeed.Balanced
}
Dim results As BarcodeResults = BarcodeReader.Read("label.png", options)Minimal Workflow (5 steps)
- Download the IronBarcode library from NuGet
- Create a
BarcodeReaderOptionsinstance - Set
ExpectBarcodeTypesto the symbologies present in the pipeline - Enable
RemoveFalsePositivefor secondary verification - Call
BarcodeReader.Readto decode, checksums are validated automatically during decode
How to Validate Barcode Checksums?
IronBarcode validates checksums during decoding according to each symbology's specification. For example, when reading an EAN-13 barcode, the Mod10 check digit is calculated from the first 12 digits and compared to the 13th. If the digits do not match, the barcode is silently rejected and does not appear in the BarcodeResults collection. This approach applies to all formats with a mandatory check digit, including UPC-A, UPC-E, EAN-8, Code128, ITF, and others.
This implicit model differs from libraries that expose an explicit toggle. The table below compares the two approaches:
| Aspect | IronBarcode | Aspose.BarCode |
|---|---|---|
| Validation trigger | Automatic; runs during every decode | Explicit: ChecksumValidation.On / Off / Default |
| Developer action required | None; invalid barcodes are excluded from results | Set BarcodeSettings.ChecksumValidation before reading |
| Checksum disable | Not exposed; checksums are always enforced for mandatory formats | Yes; ChecksumValidation.Off skips verification |
| Optional-checksum formats (Code39) | Uses Confidence + RemoveFalsePositive to filter low-quality reads | Explicitly enable with EnableChecksum.Yes |
| Failure behavior | Barcode silently omitted from results | Barcode may appear with a separate checksum value for manual inspection |
For symbologies with optional checksums, such as Code39, the library uses confidence scoring and RemoveFalsePositive instead of a checksum toggle.
Input
A Code128 warehouse rack label (success path) and a blank image with no barcode (failure path).

warehouse-rack.png (success path)

blank-no-barcode.png (failure path - no barcode present)
using IronBarCode;
// Constrain reads to 1D formats and enable secondary verification.
// ConfidenceThreshold rejects decodes where the ML detector falls below 85%,
// acting as a quality gate for optional-checksum symbologies like Code39.
var options = new BarcodeReaderOptions
{
ExpectBarcodeTypes = BarcodeEncoding.AllOneDimensional,
RemoveFalsePositive = true,
ConfidenceThreshold = 0.85,
Speed = ReadingSpeed.Detailed
};
BarcodeResults results = BarcodeReader.Read("warehouse-rack.png", options);
foreach (BarcodeResult result in results)
{
// Each result has passed checksum validation (mandatory formats)
// and the 85% confidence threshold, so no additional filtering is needed.
Console.WriteLine($"[{result.BarcodeType}] {result.Value} page={result.PageNumber}");
}
if (results.Count == 0)
{
Console.Error.WriteLine("No valid barcodes found. Possible causes:");
Console.Error.WriteLine(" - Check digit mismatch (barcode silently rejected)");
Console.Error.WriteLine(" - Confidence below 85% threshold");
Console.Error.WriteLine(" - Format not in ExpectBarcodeTypes");
}Imports IronBarCode
' Constrain reads to 1D formats and enable secondary verification.
' ConfidenceThreshold rejects decodes where the ML detector falls below 85%,
' acting as a quality gate for optional-checksum symbologies like Code39.
Dim options As New BarcodeReaderOptions With {
.ExpectBarcodeTypes = BarcodeEncoding.AllOneDimensional,
.RemoveFalsePositive = True,
.ConfidenceThreshold = 0.85,
.Speed = ReadingSpeed.Detailed
}
Dim results As BarcodeResults = BarcodeReader.Read("warehouse-rack.png", options)
For Each result As BarcodeResult In results
' Each result has passed checksum validation (mandatory formats)
' and the 85% confidence threshold, so no additional filtering is needed.
Console.WriteLine($"[{result.BarcodeType}] {result.Value} page={result.PageNumber}")
Next
If results.Count = 0 Then
Console.Error.WriteLine("No valid barcodes found. Possible causes:")
Console.Error.WriteLine(" - Check digit mismatch (barcode silently rejected)")
Console.Error.WriteLine(" - Confidence below 85% threshold")
Console.Error.WriteLine(" - Format not in ExpectBarcodeTypes")
End IfOutput
Success Path

The warehouse rack barcode came back as RACK-A1-LOT-7382 on page 0. It cleared the 85% confidence threshold and passed checksum validation, so it shows up in BarcodeResults.
Failure Path

Raising ConfidenceThreshold above its 0.7 default tightens this gate further for optional-checksum symbologies such as Code39.
With checksum validation covered, the next step is restricting the reader to the barcode formats your pipeline expects.
How to Use Format-Aware Barcode Reading?
The BarcodeEncoding enum is a flags type, allowing multiple formats to be combined using the bitwise OR operator. Setting ExpectBarcodeTypes limits the reader to those formats and skips detection for others.
| Value | Category | Description | Checksum |
|---|---|---|---|
BarcodeEncoding.All | Meta | All supported formats (default behavior) | Per-format |
BarcodeEncoding.AllOneDimensional | Meta | All linear (1D) formats including stacked | Per-format |
BarcodeEncoding.AllTwoDimensional | Meta | All matrix/grid (2D) formats | Per-format |
BarcodeEncoding.Code128 | 1D | High-density alphanumeric (logistics, shipping) | Mandatory (weighted Mod103) |
BarcodeEncoding.EAN13 | 1D | Retail product identification, 13 digits | Mandatory (Mod10) |
BarcodeEncoding.QRCode | 2D | High-capacity matrix (URLs, structured data) | Reed-Solomon ECC |
BarcodeEncoding.Code39 | 1D | Alphanumeric (defense, automotive) | Optional (Mod43) |
BarcodeEncoding.UPCA | 1D | North American retail, 12 digits | Mandatory (Mod10) |
BarcodeEncoding.DataMatrix | 2D | Compact matrix (electronics, pharma) | Reed-Solomon ECC |
BarcodeEncoding.PDF417 | 2D | Stacked (ID cards, transport) | Reed-Solomon ECC |
Beyond speed, constraining the format set acts as a validation gate: barcodes of any unlisted symbology are excluded from results even if physically present in the image.
Input
A Code128 shipping label (success path) and a QR code that does not match the Code128-only constraint (failure path).

shipping-label.png (success path - Code128 matches constraint)

qr-format-mismatch.png (failure path - QR rejected by Code128-only filter)
using IronBarCode;
// Constrained read: only Code128 barcodes are returned.
// Faster because the reader skips all other format detectors.
var constrainedOptions = new BarcodeReaderOptions
{
ExpectBarcodeTypes = BarcodeEncoding.Code128,
Speed = ReadingSpeed.Faster,
ExpectMultipleBarcodes = false
};
// Broad read: all supported formats are scanned.
// Useful for verification or when the image format is unknown.
var broadOptions = new BarcodeReaderOptions
{
ExpectBarcodeTypes = BarcodeEncoding.All,
Speed = ReadingSpeed.Detailed,
ExpectMultipleBarcodes = true
};
string imagePath = "shipping-label.png";
BarcodeResults constrained = BarcodeReader.Read(imagePath, constrainedOptions);
Console.WriteLine($"Constrained: {constrained.Count} Code128 barcode(s) found");
BarcodeResults broad = BarcodeReader.Read(imagePath, broadOptions);
Console.WriteLine($"Broad: {broad.Count} barcode(s) found across all formats");
foreach (BarcodeResult result in broad)
{
Console.WriteLine($" [{result.BarcodeType}] {result.Value}");
}Imports IronBarCode
' Constrained read: only Code128 barcodes are returned.
' Faster because the reader skips all other format detectors.
Dim constrainedOptions As New BarcodeReaderOptions With {
.ExpectBarcodeTypes = BarcodeEncoding.Code128,
.Speed = ReadingSpeed.Faster,
.ExpectMultipleBarcodes = False
}
' Broad read: all supported formats are scanned.
' Useful for verification or when the image format is unknown.
Dim broadOptions As New BarcodeReaderOptions With {
.ExpectBarcodeTypes = BarcodeEncoding.All,
.Speed = ReadingSpeed.Detailed,
.ExpectMultipleBarcodes = True
}
Dim imagePath As String = "shipping-label.png"
Dim constrained As BarcodeResults = BarcodeReader.Read(imagePath, constrainedOptions)
Console.WriteLine($"Constrained: {constrained.Count} Code128 barcode(s) found")
Dim broad As BarcodeResults = BarcodeReader.Read(imagePath, broadOptions)
Console.WriteLine($"Broad: {broad.Count} barcode(s) found across all formats")
For Each result As BarcodeResult In broad
Console.WriteLine($" [{result.BarcodeType}] {result.Value}")
NextOutput
Success Path

The shipping label has a value of SHIP-2024-00438. The constrained read picks it up straight away since Code128 is what the filter expects, and the broad read confirms the same result across all formats.
Failure Path

Empty results from a constrained read are a validation signal, not an error; log the discrepancy for review.
For pipelines that mix barcode types (e.g., a packing slip with both an EAN-13 product code and a Code128 tracking number), combine the expected formats:
using IronBarCode;
// Combine multiple format flags with | to scan for more than one symbology
// in a single pass. Each BarcodeResult.BarcodeType identifies which format
// was decoded, enabling downstream routing logic per symbology.
var options = new BarcodeReaderOptions
{
ExpectBarcodeTypes = BarcodeEncoding.EAN13 | BarcodeEncoding.Code128,
ExpectMultipleBarcodes = true
};Imports IronBarCode
' Combine multiple format flags with Or to scan for more than one symbology
' in a single pass. Each BarcodeResult.BarcodeType identifies which format
' was decoded, enabling downstream routing logic per symbology.
Dim options As New BarcodeReaderOptions With {
.ExpectBarcodeTypes = BarcodeEncoding.EAN13 Or BarcodeEncoding.Code128,
.ExpectMultipleBarcodes = True
}Each returned BarcodeResult.BarcodeType identifies which format was decoded, enabling downstream routing.
Which Symbologies Support Checksum Validation?
Not all barcode formats use checksums in the same way. The following table maps common symbologies to their error-detection characteristics, which informs how aggressively to set ConfidenceThreshold and RemoveFalsePositive for each format:
| Symbology | Checksum Type | Mandatory? | Recommendation |
|---|---|---|---|
| EAN-13 / EAN-8 | Mod10 | Yes | Default settings sufficient; checksum always enforced |
| UPC-A / UPC-E | Mod10 | Yes | Default settings sufficient; check digit auto-corrected on write |
| Code128 | Weighted Mod103 | Yes | Default settings sufficient; mandatory per specification |
| Code39 | Mod43 | Optional | Raise ConfidenceThreshold to 0.8+ and enable RemoveFalsePositive |
| Codabar | Mod16 | Optional | Same as Code39; use confidence as the quality gate |
| ITF | Mod10 | Optional | Enable RemoveFalsePositive for interleaved formats |
| QRCode / DataMatrix | Reed-Solomon ECC | Always | Structural error correction; no additional configuration needed |
| PDF417 | Reed-Solomon ECC | Always | Same as QR/DataMatrix; error correction is inherent |
For 2D symbologies such as QR, DataMatrix, and PDF417, error correction is integrated into the encoding structure. These formats can recover from partial damage without depending on a simple check digit. The ConfidenceThreshold still applies during the ML detection phase, while the decode step benefits from the symbology's built-in redundancy.
Now that both techniques are understood, let's combine them into a single production-ready validation pattern.
How to Combine Checksums with Format Constraints?
The production-ready pattern sets ExpectBarcodeTypes, RemoveFalsePositive, ConfidenceThreshold, and Speed in a single BarcodeReaderOptions object. Together they form a layered gate: format constraints narrow the search space, checksum validation ensures data integrity, confidence thresholding filters marginal decodes, and false-positive removal adds a secondary verification pass.
Input
Three POS scan barcodes from the pos-scans/ directory used as the success path: two EAN-13 and one UPC-A. A Code128 warehouse rack label is used as the failure path - the EAN-13/UPC-A constraint rejects it and logs a REJECT line.

pos-scan-1.png (success)

pos-scan-2.png (success)

pos-scan-3.png (success)

warehouse-rack.png (failure - Code128 rejected)
using IronBarCode;
// Layered validation for retail POS: EAN-13, UPC-A, and UPC-E only.
// Each property adds a distinct filter to the read pipeline.
var options = new BarcodeReaderOptions
{
// Layer 1: format constraint, accept only retail symbologies
ExpectBarcodeTypes = BarcodeEncoding.EAN13 | BarcodeEncoding.UPCA | BarcodeEncoding.UPCE,
// Layer 2: confidence threshold, reject decodes below 80%
ConfidenceThreshold = 0.8,
// Layer 3: false-positive removal, runs a secondary verification pass
RemoveFalsePositive = true,
Speed = ReadingSpeed.Balanced,
ExpectMultipleBarcodes = false,
// Require 3 agreeing scan lines to reduce phantom reads from noisy images
MinScanLines = 3
};
string[] scanFiles = Directory.GetFiles("pos-scans/", "*.png");
foreach (string file in scanFiles)
{
BarcodeResults results = BarcodeReader.Read(file, options);
if (results.Count == 0)
{
// No barcode passed all validation layers
Console.Error.WriteLine($"REJECT {Path.GetFileName(file)}: "
+ "no valid EAN-13/UPC barcode (checksum, confidence, or format mismatch)");
continue;
}
BarcodeResult primary = results.First();
// Post-read assertion: verify the decoded format matches expectations.
// ExpectBarcodeTypes already constrains the reader; this check documents
// intent and surfaces unexpected results during future changes.
if (primary.BarcodeType != BarcodeEncoding.EAN13
&& primary.BarcodeType != BarcodeEncoding.UPCA
&& primary.BarcodeType != BarcodeEncoding.UPCE)
{
Console.Error.WriteLine($"UNEXPECTED FORMAT {Path.GetFileName(file)}: "
+ $"got {primary.BarcodeType}, expected EAN-13/UPC");
continue;
}
Console.WriteLine($"OK {Path.GetFileName(file)}: [{primary.BarcodeType}] {primary.Value}");
}Imports IronBarCode
Imports System.IO
' Layered validation for retail POS: EAN-13, UPC-A, and UPC-E only.
' Each property adds a distinct filter to the read pipeline.
Dim options As New BarcodeReaderOptions With {
' Layer 1: format constraint, accept only retail symbologies
.ExpectBarcodeTypes = BarcodeEncoding.EAN13 Or BarcodeEncoding.UPCA Or BarcodeEncoding.UPCE,
' Layer 2: confidence threshold, reject decodes below 80%
.ConfidenceThreshold = 0.8,
' Layer 3: false-positive removal, runs a secondary verification pass
.RemoveFalsePositive = True,
.Speed = ReadingSpeed.Balanced,
.ExpectMultipleBarcodes = False,
' Require 3 agreeing scan lines to reduce phantom reads from noisy images
.MinScanLines = 3
}
Dim scanFiles As String() = Directory.GetFiles("pos-scans/", "*.png")
For Each file As String In scanFiles
Dim results As BarcodeResults = BarcodeReader.Read(file, options)
If results.Count = 0 Then
' No barcode passed all validation layers
Console.Error.WriteLine($"REJECT {Path.GetFileName(file)}: " &
"no valid EAN-13/UPC barcode (checksum, confidence, or format mismatch)")
Continue For
End If
Dim primary As BarcodeResult = results.First()
' Post-read assertion: verify the decoded format matches expectations.
' ExpectBarcodeTypes already constrains the reader; this check documents
' intent and surfaces unexpected results during future changes.
If primary.BarcodeType <> BarcodeEncoding.EAN13 AndAlso
primary.BarcodeType <> BarcodeEncoding.UPCA AndAlso
primary.BarcodeType <> BarcodeEncoding.UPCE Then
Console.Error.WriteLine($"UNEXPECTED FORMAT {Path.GetFileName(file)}: " &
$"got {primary.BarcodeType}, expected EAN-13/UPC")
Continue For
End If
Console.WriteLine($"OK {Path.GetFileName(file)}: [{primary.BarcodeType}] {primary.Value}")
NextOutput
Success Path

All three POS scan images made it through. The reader returned values of 5901234123471, 4006381333931, and 012345678905. Each one matched the EAN13 | UPCA | UPCE filter, had a valid Mod10 checksum, and confidence was above 0.8.
Failure Path

Setting MinScanLines to 3 increases the minimum number of agreeing scan lines required for a 1D barcode to be valid; the default is 2. Raising this value lowers the risk of phantom reads from noisy scan lines but may cause thin or partially damaged barcodes to be missed. In retail POS environments with clean printed labels, a value of 3 is a conservative choice that strengthens validation without affecting throughput.
The post-read BarcodeType assertion is defense-in-depth: ExpectBarcodeTypes already filters, but the explicit check documents intent and catches configuration drift without runtime cost. For speed tuning, ReadingSpeed.Faster suits clean machine-printed labels; Detailed and ExtremeDetail recover damaged or poorly lit barcodes at the cost of longer scan times.
What Are My Next Steps?
This article covered IronBarcode's implicit checksum validation model, the BarcodeEncoding flags enum for format-constrained reads, and a combined validation pattern using ExpectBarcodeTypes, ConfidenceThreshold, RemoveFalsePositive, and MinScanLines as layered quality gates.
For further reading, explore these resources:
- IronBarcode Tutorials - Reading Barcodes for end-to-end reading walkthroughs.
- False Positive Prevention for the
RemoveFalsePositivemechanism in detail. - Confidence Threshold Examples for ML-based detection tuning.
- Output Data Formats for
BarcodeResultproperty reference. - Image Correction How-To for filters that improve decode accuracy.
- BarcodeReaderOptions API Reference for complete configuration documentation.
- BarcodeEncoding API Reference for the full list of supported symbologies.
Get a free trial license to test every feature in a live environment, or view licensing options when the pipeline is ready for production.
Frequently Asked Questions
What is the purpose of validating barcode checksums?
Validating barcode checksums ensures that data is not corrupted during barcode scanning. IronBarcode automatically performs checksum verification for each symbology's check-digit algorithm during decoding.
How does IronBarcode handle format-aware reading?
IronBarcode uses the `BarcodeReaderOptions.ExpectBarcodeTypes` property to restrict reads to specific barcode symbologies. This reduces false positives and improves scanning efficiency by limiting format detectors to only expected types.
Can IronBarcode perform automatic checksum verification?
Yes, IronBarcode performs automatic checksum verification during the decoding process. Barcodes that fail this verification are discarded before results are returned.
What is the use of the `RemoveFalsePositive` feature in IronBarcode?
The `RemoveFalsePositive` feature in IronBarcode adds a secondary scan verification to help eliminate ambiguous reads, ensuring higher accuracy in barcode detection.
Which symbologies support mandatory checksum validation in IronBarcode?
Symbologies such as EAN-13, UPC-A, Code128, and others support mandatory checksum validation. IronBarcode automatically enforces checksum checks for these formats.
How can you set constraints on barcode reading formats with IronBarcode?
You can set constraints on barcode reading formats in IronBarcode using the `ExpectBarcodeTypes` property. It allows you to specify and limit the barcode types IronBarcode should decode.
What are the benefits of using format constraints in barcode reading?
Format constraints help in reducing scanning errors by limiting the search to specific symbologies, thus avoiding unnecessary noise, and enhancing the scanning speed.
How does IronBarcode handle barcodes with optional checksum formats like Code39?
For optional checksum formats like Code39, IronBarcode uses a combination of confidence scoring and the `RemoveFalsePositive` feature to filter out low-quality reads.
What does the ConfidenceThreshold property do in IronBarcode?
The `ConfidenceThreshold` property in IronBarcode sets a quality gate for decoding, rejecting barcodes where the machine learning detector's confidence falls below a specified percentage.
How can IronBarcode combine checksum validation with format constraints?
IronBarcode combines checksum validation with format constraints using `BarcodeReaderOptions`. By setting properties like `ExpectBarcodeTypes`, `ConfidenceThreshold`, and `RemoveFalsePositive`, it creates a layered validation approach.

Curtis Chau holds a Bachelor’s degree in Computer Science (Carleton University) and specializes in front-end development with expertise in Node.js, TypeScript, JavaScript, and React. Passionate about crafting intuitive and aesthetically pleasing user interfaces, Curtis enjoys working with modern frameworks and creating well-structured, visually appealing manuals.