Humanizr/Humanizer · error · OverflowException

Cannot safely negate long.MinValue.

Error message

Cannot safely negate long.MinValue.

What it means

OverflowException guard inside the WholePhrasePrefix ordinal path: negating long.MinValue is undefined in two's complement, so the renderer refuses it rather than producing a wrapped value. Note that the shipped public API is ConvertToOrdinal(int), and int.MinValue (cast to long) is never equal to long.MinValue, so this branch is currently unreachable through the public ordinal entry point; the guard is defensive for any future long-based ordinal caller of ConvertWholePhraseOrdinal.

Source

Thrown at src/Humanizer/Localisation/NumberToWords/ConjunctionalScaleNumberToWordsConverter.cs:193

            }

            parts.Add(string.Concat(
                tens,
                profile.TensUnitsSeparator,
                GetUnitValue(units, isOrdinal)));
            return;
        }

        parts.Add(GetUnitValue(number, isOrdinal));
    }

    string ConvertWholePhraseOrdinal(long number, bool addAnd)
    {
        if (number < 0)
        {
            if (number == long.MinValue)
            {
                throw new OverflowException("Cannot safely negate long.MinValue.");
            }

            return $"{profile.MinusWord} {ConvertWholePhraseOrdinal(-number, addAnd)}";
        }

        if (number < profile.OrdinalUnitsMap.Length)
        {
            return GetUnitValue(number, isOrdinal: true);
        }

        return $"{profile.OrdinalWholePhrasePrefix}{ConvertCore(number, isOrdinal: false, addAnd)}";
    }

    string GetUnitValue(long number, bool isOrdinal) =>
        isOrdinal ? profile.OrdinalUnitsMap[number] : profile.UnitsMap[number];

    // "and" placement is modeled as a structural rule family rather than as locale branches.
    // The generated profile says which insertion points are legal, and this method translates that

View on GitHub (pinned to ffc2b77c0f)

Solutions

  1. No action needed for the current int-based ordinal API.
  2. If adding a long ordinal overload, reject long.MinValue at the entry point before delegating to ConvertWholePhraseOrdinal.
Defensive patterns

Strategy: validation

Validate before calling

// Currently unreachable via ConvertToOrdinal(int); guard only if you add a long ordinal overload:
static string SafeOrdinalWords(long number)
{
    if (number == long.MinValue)
    {
        throw new ArgumentOutOfRangeException(nameof(number), number, "long.MinValue has no negatable ordinal form.");
    }
    // ...delegate to the converter
}

Prevention

When it happens

Trigger: Not reachable via the public ConvertToOrdinal(int) API today, since int.MinValue != long.MinValue. Would only fire if a future overload invoked ConvertWholePhraseOrdinal(long.MinValue, addAnd) directly while OrdinalMode == WholePhrasePrefix.

Common situations: Not user-reachable in the current release; documented for completeness and for anyone extending the converter with a long ordinal overload.

Related errors


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