nopSolutions/nopCommerce · warning · NopException

Unsupported file structure

Error message

Unsupported file {AvalaraTaxDefaults.TaxRatesFilePath} structure

What it means

The fallback CSV's first line (header) splits into fewer than 14 comma-separated columns, so the parser does not recognize the schema. The expected layout has ZIP_CODE, STATE_ABBREV, COUNTY_NAME, plus rate columns; fewer than 14 columns means the file is the wrong format.

Solutions

  1. Open the file and inspect the header row to confirm what was actually downloaded.
  2. Delete the malformed file and re-download to obtain the current schema.
  3. Verify the plugin version matches the current Avalara rate-file format; upgrade if schema changed.
  4. If the schema legitimately changed, update the parser column indices.

Example fix

// before
if (!lines.Any() || lines[0].Split(',').Length < 14)
    throw new NopException($"Unsupported file {AvalaraTaxDefaults.TaxRatesFilePath} structure");

// after - report what was found vs expected
var headerColumns = lines.ElementAtOrDefault(0)?.Split(',').Length ?? 0;
if (!lines.Any() || headerColumns < 14)
    throw new NopException($"Unsupported structure in {AvalaraTaxDefaults.TaxRatesFilePath}: expected >= 14 columns, found {headerColumns}. Re-download the file or update the plugin.");
Defensive patterns

Strategy: validation

Validate before calling

// Sanity-check the header before parsing
var firstLine = (await _fileProvider.ReadAllTextAsync(filePath, Encoding.UTF8))
    ?.Split(Environment.NewLine, StringSplitOptions.RemoveEmptyEntries).FirstOrDefault();
if (firstLine is null || firstLine.Split(',').Length < 14)
    throw new NopException($"Unsupported rates-file structure in {AvalaraTaxDefaults.TaxRatesFilePath}");

Prevention

When it happens

Trigger: The downloaded file is a different format or version than expected, or a non-CSV payload (e.g., an HTML error page) was saved with the .csv extension, so the header line yields too few columns.

Common situations: Avalara changed the rate-file schema; an error page got saved as the rates file; a locale using a different list separator; a partial download that truncated columns; an older plugin version against a newer file.

Related errors


AI-assisted analysis of nopSolutions/nopCommerce@64bdf2ff08 (2026-08-13). Data as JSON: /api/errors/3292cd9a42992083. Report an issue: GitHub.

Appendix: source

Thrown at src/Plugins/Nop.Plugin.Tax.Avalara/Services/AvalaraTaxManager.cs:677

    /// </returns>
    protected async Task<List<TaxRate>> GetTaxRatesFromFileAsync()
    {
        //try to create file if doesn't exist
        var filePath = _fileProvider.MapPath(AvalaraTaxDefaults.TaxRatesFilePath);
        if (!_fileProvider.FileExists(filePath))
            await DownloadTaxRatesAsync();

        if (!_fileProvider.FileExists(filePath))
            throw new NopException($"File {AvalaraTaxDefaults.TaxRatesFilePath} not found");

        //get file lines
        var text = await _fileProvider.ReadAllTextAsync(filePath, Encoding.UTF8);
        if (string.IsNullOrEmpty(text))
            throw new NopException($"File {AvalaraTaxDefaults.TaxRatesFilePath} is empty");

        var lines = text.Split(Environment.NewLine, StringSplitOptions.RemoveEmptyEntries);
        if (!lines.Any() || lines[0].Split(',').Length < 14)
            throw new NopException($"Unsupported file {AvalaraTaxDefaults.TaxRatesFilePath} structure");

        //prepare tax rates
        var taxRates = lines.Skip(1).Select(line =>
        {
            try
            {
                var values = line.Split(',', StringSplitOptions.TrimEntries);
                return new TaxRate
                {
                    Zip = values[0], //ZIP_CODE
                    State = values[1], //STATE_ABBREV
                    County = values[2], //COUNTY_NAME
                    City = values[3], //CITY_NAME
                    StateTax = decimal.Parse(values[4], NumberStyles.Any, CultureInfo.InvariantCulture), //STATE_SALES_TAX
                    CountyTax = decimal.Parse(values[6], NumberStyles.Any, CultureInfo.InvariantCulture), //COUNTY_SALES_TAX
                    CityTax = decimal.Parse(values[8], NumberStyles.Any, CultureInfo.InvariantCulture), //CITY_SALES_TAX
                    TotalTax = decimal.Parse(values[10], NumberStyles.Any, CultureInfo.InvariantCulture), //TOTAL_SALES_TAX
                    ShippingTaxable = string.Equals(values[11], "y", StringComparison.InvariantCultureIgnoreCase), //TAX_SHIPPING_ALONE

View on GitHub (pinned to 64bdf2ff08)