CSVHelper: Header with name not found

By FoxLearn 3/6/2025 2:57:37 AM   59
When your CSV file’s header names do not match the property names in your class, CsvHelper will throw an error.

For example, if your CSV header is “product” and your class property is “Product,” it will trigger an exception like this: HeaderValidationException: Header with name ‘Product’[0] was not found.

If changing the property names to match the headers isn’t an option, you can configure CsvHelper to match headers with different property names.

Here are three solutions:

  1. Use the [Name] attribute on properties that need mapping.
  2. Use CsvConfiguration.PrepareHeaderForMatch for patterns in naming differences (like casing).
  3. Use a ClassMap to explicitly define the header-to-property mappings.

Below are examples of how to apply each method.

Option 1 – Use the [Name] Attribute

The easiest way to map a CSV header to a property with a different name is by using CsvHelper’s [Name] attribute.

For example, CSV with the ProdName header:

Product,Price,ProdName
Laptop,1000,Dell
Phone,500,Apple
Tablet,300,Samsung

For example, How to map the ProdName header to the Manufacturer property using the [Name] attribute:

using CsvHelper.Configuration.Attributes;

public class Product
{
    [Name("ProdName")]
    public string Manufacturer { get; set; }
    public string Product { get; set; }
    public int Price { get; set; }
}

Now, when parsing the CSV file, CsvHelper will correctly map the ProdName column to the Manufacturer property.

using CsvHelper;
using System.Globalization;

using (var reader = new StreamReader(@"C:\products.csv"))
{
    using var csvReader = new CsvReader(reader, CultureInfo.InvariantCulture);

    foreach (var product in csvReader.GetRecords<Product>())
    {
        Console.WriteLine($"Product: {product.Product} (${product.Price}), Manufacturer: {product.Manufacturer}");
    }
}

This will output:

Product: Laptop ($1000), Manufacturer: Dell
Product: Phone ($500), Manufacturer: Apple
Product: Tablet ($300), Manufacturer: Samsung

Option 2 – Use PrepareHeaderForMatch

When the difference in naming is consistent (e.g., a case difference), you can use CsvConfiguration.PrepareHeaderForMatch to standardize header names before matching them to properties.

Here’s an example where the CSV headers are all uppercase:

PRODUCT,PRICE,MANUFACTURER
Laptop,1000,Dell
Phone,500,Apple
Tablet,300,Samsung

With the class properties in Pascal case:

public class Product
{
    public string Manufacturer { get; set; }
    public string Product { get; set; }
    public int Price { get; set; }
}

To make the header names case-insensitive, we can use PrepareHeaderForMatch to transform the header names to lowercase:

using CsvHelper;
using CsvHelper.Configuration;
using System.Globalization;

var config = new CsvConfiguration(CultureInfo.InvariantCulture)
{
    PrepareHeaderForMatch = (args) => args.Header.ToLower()
};

using (var reader = new StreamReader(@"C:\products-uppercase.csv"))
{
    using var csvReader = new CsvReader(reader, config);

    foreach (var product in csvReader.GetRecords<Product>())
    {
        Console.WriteLine($"Product: {product.Product} (${product.Price}), Manufacturer: {product.Manufacturer}");
    }
}

This will output:

Product: Laptop ($1000), Manufacturer: Dell
Product: Phone ($500), Manufacturer: Apple
Product: Tablet ($300), Manufacturer: Samsung

Option 3 – Use a ClassMap

If you need precise control over the header-to-property mapping, you can use a ClassMap to declare explicit mappings.

Given the following CSV:

Product Name,Cost,Manufacturer Name
Laptop,1000,Dell
Phone,500,Apple
Tablet,300,Samsung

To map the headers to the Product, Price, and Manufacturer properties, you would create a ClassMap like this:

using CsvHelper.Configuration;

public class ProductMap : ClassMap<Product>
{
    public ProductMap()
    {
        Map(product => product.Product).Name("Product Name");
        Map(product => product.Price).Name("Cost");
        Map(product => product.Manufacturer).Name("Manufacturer Name");
    }
}

Then, register the ClassMap when parsing the CSV:

using CsvHelper;
using System.Globalization;

using (var reader = new StreamReader(@"C:\products-mapped.csv"))
{
    using var csvReader = new CsvReader(reader, CultureInfo.InvariantCulture);
    csvReader.Context.RegisterClassMap<ProductMap>();

    foreach (var product in csvReader.GetRecords<Product>())
    {
        Console.WriteLine($"Product: {product.Product} (${product.Price}), Manufacturer: {product.Manufacturer}");
    }
}

This will output:

Product: Laptop ($1000), Manufacturer: Dell
Product: Phone ($500), Manufacturer: Apple
Product: Tablet ($300), Manufacturer: Samsung

The drawback of using a ClassMap is that you must explicitly define every property-to-header mapping. If a property does not have an explicit mapping, CsvHelper will not populate it.

With these three options, you can easily handle situations where your CSV headers don’t match your property names. Choose the one that best suits your needs depending on the complexity and consistency of your naming differences.