Humanizr/Humanizer · error · FormatException

Unit token '{unit.Symbol}' does not belong to the selected b

Error message

Unit token '{unit.Symbol}' does not belong to the selected byte-size unit system.

What it means

Thrown by ByteSize.FindFormatUnit while interpreting a format string for a chosen unit system. After masking quoted/escaped literals, if the format contains a symbol belonging to the opposite system (e.g. a binary 'GiB' token while formatting with DecimalSi units, or a decimal 'GB' while using BinaryIec), the library refuses to silently mis-render it.

Source

Thrown at src/Humanizer/Bytes/ByteSize.cs:1028

        return absoluteBytes >= 1
            ? new(1, ByteSymbol, DataUnit.Byte)
            : new(1d / BitsInByte, BitSymbol, DataUnit.Bit);
    }

    static SystemUnit? FindFormatUnit(string? format, SystemUnit[] units)
    {
        if (string.IsNullOrWhiteSpace(format) || format == "G")
        {
            return null;
        }

        var maskedFormat = MaskFormatLiterals(format!);
        var incompatibleUnits = ReferenceEquals(units, DecimalUnits) ? BinaryUnits : DecimalUnits;
        foreach (var unit in incompatibleUnits)
        {
            if (maskedFormat.Contains(unit.Symbol, StringComparison.OrdinalIgnoreCase))
            {
                throw new FormatException($"Unit token '{unit.Symbol}' does not belong to the selected byte-size unit system.");
            }
        }

        if (maskedFormat.Contains("EiB", StringComparison.OrdinalIgnoreCase))
        {
            throw new FormatException("EiB is outside the range supported by ByteSize.Bits.");
        }

        SystemUnit? selectedUnit = null;
        var remainingFormat = maskedFormat;
        foreach (var unit in units)
        {
            if (!remainingFormat.Contains(unit.Symbol, StringComparison.OrdinalIgnoreCase))
            {
                continue;
            }

            if (selectedUnit is not null && selectedUnit.Value.DataUnit != unit.DataUnit)

View on GitHub (pinned to ffc2b77c0f)

Solutions

  1. Match the format string's unit token to the active unit system (decimal SI uses kB/MB/GB/TB/PB/EB; binary IEC uses KiB/MiB/GiB/TiB/PiB).
  2. If you genuinely want both, render twice with separate unit systems and concatenate.
  3. Quote literal text containing unit-like letters with single quotes (e.g. '#.## "GiB"') so MaskFormatLiterals hides them from the scan.

Example fix

// before (DecimalSi context)
var text = size.ToString("#.## GiB");

// after
var text = size.ToString("#.## GB"); // token matches DecimalSi
// or, if GiB was intentional, switch the unit system first
Defensive patterns

Strategy: validation

Validate before calling

static string NormalizeFormat(string format, ByteSizeUnitSystem system)
{
    var binary = new HashSet<string> { "KiB", "MiB", "GiB", "TiB", "PiB" };
    var decimalSi = new HashSet<string> { "kB", "MB", "GB", "TB", "PB", "EB" };
    var disallowed = system == ByteSizeUnitSystem.BinaryIec ? decimalSi : binary;
    foreach (var token in disallowed)
        if (format.Contains(token, StringComparison.OrdinalIgnoreCase))
            throw new ArgumentException($"Format contains incompatible token {token}.");
    return format;
}

Try / catch

try { return size.ToString(format); }
catch (FormatException) { throw new ArgumentException("Format token does not match the active unit system.", nameof(format)); }

Prevention

When it happens

Trigger: Calling ToString("#.## GiB", ...) on a ByteSize whose current unit system is DecimalSi, or calling Humanize with a format string that mixes 'MB' into a BinaryIec format. The masked format is scanned case-insensitively against the incompatible unit list.

Common situations: Copy-pasting a format string between code paths that use different unit systems, localizing UI where the format string comes from a resource file keyed to the wrong system, or upgrading to a version that enforces system-token separation that was previously lenient.

Related errors


AI-assisted analysis of Humanizr/Humanizer@ffc2b77c0f (2026-08-13). Data as JSON: /api/errors/ee00e1971ec0bcc1. Report an issue: GitHub.