SixLabors/ImageSharp · error · ArgumentException

Output span must be at least half the length of the input…

Error message

Output span must be at least half the length of the input string

What it means

HexStringToBytes requires the destination byte span to be at least half the length of the input character span, because each pair of hex chars yields one byte. A too-small destination throws an ArgumentException.

Solutions

  1. Allocate the destination as chars.Length / 2 bytes (or larger) before the call.
  2. Use the returned byte count instead of assuming a fixed buffer size.
  3. Catch ArgumentException and grow/reallocate the buffer.

Example fix

// before
byte[] dest = new byte[hex.Length / 3];
HexConverter.HexStringToBytes(hex.AsSpan(), dest);
// after
byte[] dest = new byte[hex.Length / 2];
int written = HexConverter.HexStringToBytes(hex.AsSpan(), dest);
Defensive patterns

Strategy: validation

Validate before calling

byte[] dest = new byte[hex.Length / 2];
Debug.Assert(dest.Length << 1 >= hex.Length);

Try / catch

try { written = HexConverter.HexStringToBytes(chars, dest); }
catch (ArgumentException ex) when (ex.ParamName == nameof(dest))
{ dest = new byte[chars.Length / 2]; written = HexConverter.HexStringToBytes(chars, dest); }

Prevention

When it happens

Trigger: Calling HexStringToBytes(chars, bytes) where bytes.Length < chars.Length / 2, e.g. allocating Convert.FromHexString-style output from an incorrect length formula.

Common situations: Allocating the destination with chars.Length instead of (chars.Length + 1) / 2; reusing a smaller buffer across calls; misreading the API's length contract.

Related errors


AI-assisted analysis of SixLabors/ImageSharp@59ce6af6fc (2026-09-13). Data as JSON: /api/errors/a77aad60561a0d18. Report an issue: GitHub.

Appendix: source

Thrown at src/ImageSharp/Common/Helpers/HexConverter.cs:26

internal static class HexConverter
{
    /// <summary>
    /// Parses a hexadecimal string into a byte array without allocations. Throws on non-hexadecimal character.
    /// Adapted from https://source.dot.net/#System.Private.CoreLib/Convert.cs,c9e4fbeaca708991.
    /// </summary>
    /// <param name="chars">The hexadecimal string to parse.</param>
    /// <param name="bytes">The destination for the parsed bytes. Must be at least <paramref name="chars"/>.Length / 2 bytes long.</param>
    /// <returns>The number of bytes written to <paramref name="bytes"/>.</returns>
    public static int HexStringToBytes(ReadOnlySpan<char> chars, Span<byte> bytes)
    {
        if (Numerics.Modulo2(chars.Length) != 0)
        {
            throw new ArgumentException("Input string length must be a multiple of 2", nameof(chars));
        }

        if ((bytes.Length << 1 /* bit-hack for *2 */) < chars.Length)
        {
            throw new ArgumentException("Output span must be at least half the length of the input string");
        }

        // Slightly better performance in the loop below, allows us to skip a bounds check
        // while still supporting output buffers that are larger than necessary
        bytes = bytes[..(chars.Length >> 1)];   // bit-hack for / 2

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        static int FromChar(int c)
        {
            // Map from an ASCII char to its hex value, e.g. arr['b'] == 11. 0xFF means it's not a hex digit.
            // This doesn't actually allocate.
            ReadOnlySpan<byte> charToHexLookup =
            [
                0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 15
                0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 31
                0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 47
                0x0,  0x1,  0x2,  0x3,  0x4,  0x5,  0x6,  0x7,  0x8,  0x9,  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 63
                0xFF, 0xA,  0xB,  0xC,  0xD,  0xE,  0xF,  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 79

View on GitHub (pinned to 59ce6af6fc)