How to Debug QR Code Operations and Handle Error Messages in C#

QR code pipelines that process hundreds of images per hour need structured error handling — not just try-catch, but diagnostic output that tells an on-call engineer exactly which file failed, what the input looked like, and whether the failure was a corrupt image, a capacity limit, or a missing dependency. Silent empty results are as dangerous as unhandled exceptions when there is no logging to distinguish "no QR found" from "input was invalid."

IronQR provides QrReader for reading and QrWriter for generation. Unlike IronBarcode, IronQR does not define a custom exception hierarchy — operations throw standard .NET exceptions (ArgumentNullException, ArgumentException, IOException), which means we structure our catch blocks around the BCL types and extract diagnostics from the context we control. We cover read-time errors, write-time errors, and a reusable logging wrapper below.

Quickstart: Handle QR Code Errors

Wrap QR read operations in a try-catch block and log diagnostics for file and decode failures.

  1. Install IronQR with NuGet Package Manager

    PM > Install-Package IronQR
  2. Copy and run this code snippet.

    using IronQr;
    using IronSoftware.Drawing;
    
    try
    {
        var input = new QrImageInput(AnyBitmap.FromFile("label.png"));
        var results = new QrReader().Read(input);
        Console.WriteLine($"Found {results.Count()} QR code(s)");
    }
    catch (IOException ex)
    {
        Console.Error.WriteLine($"File error: {ex.Message}");
    }
  3. Deploy to test on your live environment

    Start using IronQR in your project today with a free trial

    arrow pointer

How to Get Detailed Error Messages from QR Code Reading?

We handle read-time failures by catching exceptions from AnyBitmap.FromFile() (file access) and QrReader.Read() (decode), then inspecting the empty-result case separately. A read that finds no QR codes returns an empty IEnumerable<QrResult> rather than throwing — this is expected behavior, not an error, but it still needs to be logged as a diagnostic event in a production pipeline.

:path=/static-assets/qr/content-code-examples/how-to/detailed-error-messages/read-diagnostics.cs
using IronQr;
using IronSoftware.Drawing;

string filePath = "damaged-scan.png";

try
{
    // File-level failure throws IOException or FileNotFoundException
    var inputBmp = AnyBitmap.FromFile(filePath);
    var imageInput = new QrImageInput(inputBmp);

    var reader = new QrReader();
    IEnumerable<QrResult> results = reader.Read(imageInput);

    if (!results.Any())
    {
        // Not an exception — but a diagnostic event worth logging
        Console.Error.WriteLine($"[WARN] No QR codes found in: {filePath}");
        Console.Error.WriteLine($"  Action: Verify image quality or try a different scan");
    }
    else
    {
        foreach (QrResult result in results)
        {
            Console.WriteLine($"[{result.QrType}] {result.Value}");
        }
    }
}
catch (FileNotFoundException)
{
    Console.Error.WriteLine($"[ERROR] File not found: {filePath}");
}
catch (IOException ex)
{
    Console.Error.WriteLine($"[ERROR] Cannot read file: {filePath} — {ex.Message}");
}
catch (Exception ex)
{
    Console.Error.WriteLine($"[ERROR] Unexpected failure reading {filePath}: {ex.GetType().Name} — {ex.Message}");
}
Imports IronQr
Imports IronSoftware.Drawing

Module Module1
    Sub Main()
        Dim filePath As String = "damaged-scan.png"

        Try
            ' File-level failure throws IOException or FileNotFoundException
            Dim inputBmp = AnyBitmap.FromFile(filePath)
            Dim imageInput = New QrImageInput(inputBmp)

            Dim reader = New QrReader()
            Dim results As IEnumerable(Of QrResult) = reader.Read(imageInput)

            If Not results.Any() Then
                ' Not an exception — but a diagnostic event worth logging
                Console.Error.WriteLine($"[WARN] No QR codes found in: {filePath}")
                Console.Error.WriteLine("  Action: Verify image quality or try a different scan")
            Else
                For Each result As QrResult In results
                    Console.WriteLine($"[{result.QrType}] {result.Value}")
                Next
            End If
        Catch ex As FileNotFoundException
            Console.Error.WriteLine($"[ERROR] File not found: {filePath}")
        Catch ex As IOException
            Console.Error.WriteLine($"[ERROR] Cannot read file: {filePath} — {ex.Message}")
        Catch ex As Exception
            Console.Error.WriteLine($"[ERROR] Unexpected failure reading {filePath}: {ex.GetType().Name} — {ex.Message}")
        End Try
    End Sub
End Module
$vbLabelText   $csharpLabel

The QrResult object exposes three diagnostic fields: Value (the decoded string), Points (four corner coordinates of the detected QR region), and QrType (one of QRCode, MicroQRCode, or RMQRCode). When a read produces partial or unexpected results, the QrType field helps identify whether the scanner detected a standard QR or a variant format.


How to Debug QR Code Generation Failures?

QrWriter.Write() throws when the input violates QR encoding constraints. Passing null triggers an ArgumentNullException. Data that exceeds the maximum capacity for the selected error correction level throws an ArgumentException — higher correction levels (like QrErrorCorrectionLevel.Highest) reduce available data capacity, so the same string may succeed at Medium but fail at Highest.

:path=/static-assets/qr/content-code-examples/how-to/detailed-error-messages/write-diagnostics.cs
using IronQr;

string? content = null;
string oversizedContent = new string('A', 5000);

// Scenario 1: null input
try
{
    QrCode qr = QrWriter.Write(content);
}
catch (ArgumentNullException ex)
{
    Console.Error.WriteLine($"[ERROR] Null content: {ex.ParamName} — {ex.Message}");
}

// Scenario 2: data exceeds QR capacity at the configured error correction level
try
{
    var options = new QrOptions(QrErrorCorrectionLevel.Highest);
    QrCode qr = QrWriter.Write(oversizedContent, options);
}
catch (ArgumentException ex)
{
    Console.Error.WriteLine($"[ERROR] QR capacity exceeded: {ex.Message}");
    Console.Error.WriteLine($"  Input length: {oversizedContent.Length} chars");
    Console.Error.WriteLine($"  Action: Reduce content or lower error correction level");
}
Imports IronQr

Dim content As String = Nothing
Dim oversizedContent As String = New String("A"c, 5000)

' Scenario 1: null input
Try
    Dim qr As QrCode = QrWriter.Write(content)
Catch ex As ArgumentNullException
    Console.Error.WriteLine($"[ERROR] Null content: {ex.ParamName} — {ex.Message}")
End Try

' Scenario 2: data exceeds QR capacity at the configured error correction level
Try
    Dim options As New QrOptions(QrErrorCorrectionLevel.Highest)
    Dim qr As QrCode = QrWriter.Write(oversizedContent, options)
Catch ex As ArgumentException
    Console.Error.WriteLine($"[ERROR] QR capacity exceeded: {ex.Message}")
    Console.Error.WriteLine($"  Input length: {oversizedContent.Length} chars")
    Console.Error.WriteLine($"  Action: Reduce content or lower error correction level")
End Try
$vbLabelText   $csharpLabel

We log the input length alongside the exception message to give on-call engineers enough context to determine whether the fix is shorter content or a lower error correction level. The error correction article covers the capacity tradeoffs in detail — we link to it here rather than duplicating that content.

For generation workflows that accept user-supplied content, we recommend validating string length and null checks before calling QrWriter.Write(). Pre-validation is cheaper than exception handling and produces clearer diagnostic messages.


How to Log and Monitor QR Code Operations?

IronQR does not expose a product-specific logging API. The shared IronSoftware.Logger class — available across all Iron Software products — captures internal diagnostic output when enabled. For structured observability, we wrap QR operations in a helper method that records input path, result count, elapsed time, and any exceptions as machine-parseable output.

:path=/static-assets/qr/content-code-examples/how-to/detailed-error-messages/logging-wrapper.cs
using IronQr;
using IronSoftware.Drawing;
using System.Diagnostics;

// Enable shared Iron Software logging for internal diagnostics
IronSoftware.Logger.LoggingMode = IronSoftware.Logger.LoggingModes.All;
IronSoftware.Logger.LogFilePath = "ironqr-debug.log";

// Reusable wrapper for structured observability
(IEnumerable<QrResult> Results, bool Success, string Error) ReadQrWithDiagnostics(string filePath)
{
    var sw = Stopwatch.StartNew();
    try
    {
        var input = new QrImageInput(AnyBitmap.FromFile(filePath));
        var results = new QrReader().Read(input).ToList();
        sw.Stop();

        Console.WriteLine($"{{\"op\":\"qr_read\",\"file\":\"{Path.GetFileName(filePath)}\","
            + $"\"status\":\"ok\",\"count\":{results.Count},\"ms\":{sw.ElapsedMilliseconds}}}");

        return (results, true, null);
    }
    catch (Exception ex)
    {
        sw.Stop();
        string error = $"{ex.GetType().Name}: {ex.Message}";

        Console.Error.WriteLine($"{{\"op\":\"qr_read\",\"file\":\"{Path.GetFileName(filePath)}\","
            + $"\"status\":\"error\",\"exception\":\"{ex.GetType().Name}\","
            + $"\"message\":\"{ex.Message}\",\"ms\":{sw.ElapsedMilliseconds}}}");

        return (Enumerable.Empty<QrResult>(), false, error);
    }
}

// Usage: process a batch with per-file isolation
string[] files = Directory.GetFiles("qr-scans/", "*.png");
int ok = 0, fail = 0;

foreach (string file in files)
{
    var (results, success, error) = ReadQrWithDiagnostics(file);
    if (success && results.Any()) ok++;
    else fail++;
}

Console.WriteLine($"\nBatch complete: {ok} success, {fail} failed/empty out of {files.Length} files");
Imports IronQr
Imports IronSoftware.Drawing
Imports System.Diagnostics
Imports System.IO
Imports System.Linq

' Enable shared Iron Software logging for internal diagnostics
IronSoftware.Logger.LoggingMode = IronSoftware.Logger.LoggingModes.All
IronSoftware.Logger.LogFilePath = "ironqr-debug.log"

' Reusable wrapper for structured observability
Private Function ReadQrWithDiagnostics(ByVal filePath As String) As (IEnumerable(Of QrResult), Boolean, String)
    Dim sw = Stopwatch.StartNew()
    Try
        Dim input = New QrImageInput(AnyBitmap.FromFile(filePath))
        Dim results = New QrReader().Read(input).ToList()
        sw.Stop()

        Console.WriteLine($"{{""op"":""qr_read"",""file"":""{Path.GetFileName(filePath)}"",""status"":""ok"",""count"":{results.Count},""ms"":{sw.ElapsedMilliseconds}}}")

        Return (results, True, Nothing)
    Catch ex As Exception
        sw.Stop()
        Dim error As String = $"{ex.GetType().Name}: {ex.Message}"

        Console.Error.WriteLine($"{{""op"":""qr_read"",""file"":""{Path.GetFileName(filePath)}"",""status"":""error"",""exception"":""{ex.GetType().Name}"",""message"":""{ex.Message}"",""ms"":{sw.ElapsedMilliseconds}}}")

        Return (Enumerable.Empty(Of QrResult)(), False, error)
    End Try
End Function

' Usage: process a batch with per-file isolation
Dim files As String() = Directory.GetFiles("qr-scans/", "*.png")
Dim ok As Integer = 0, fail As Integer = 0

For Each file As String In files
    Dim result = ReadQrWithDiagnostics(file)
    Dim results = result.Item1
    Dim success = result.Item2
    Dim error = result.Item3

    If success AndAlso results.Any() Then
        ok += 1
    Else
        fail += 1
    End If
Next

Console.WriteLine($"\nBatch complete: {ok} success, {fail} failed/empty out of {files.Length} files")
$vbLabelText   $csharpLabel

The JSON output integrates directly with log aggregation pipelines — stdout piped to Fluentd, Datadog, or CloudWatch in a containerized deployment. The ms field surfaces latency regressions. The IronSoftware.Logger file captures internal processing details that the wrapper does not — useful for support escalation when the structured log alone does not explain a failure.

For encoding-level reliability, the error correction how-to guide covers how to tune QrErrorCorrectionLevel to improve scan resilience for damaged or partially obscured codes. Tuning error correction is a complementary strategy — it reduces the number of read failures that reach the error handling layer in the first place.


What Are My Next Steps?

We covered read-time error handling with empty-result diagnostics, write-time failure patterns for null and capacity violations, and a reusable logging wrapper that produces structured JSON output for pipeline observability.

For further reading:

View licensing options when the pipeline is ready for production.

Curtis Chau
Technical Writer

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.

...

Read More
Ready to Get Started?
Nuget Downloads 60,166 | Version: 2026.3 just released
Still Scrolling Icon

Still Scrolling?

Want proof fast? PM > Install-Package IronQR
run a sample watch your URL become a QR code.