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
- Allocate the destination as chars.Length / 2 bytes (or larger) before the call.
- Use the returned byte count instead of assuming a fixed buffer size.
- 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
- Always size the destination as chars.Length / 2 (or use stackalloc with that formula).
- Use the returned written count instead of assuming dest is fully filled.
- Add a unit test covering odd/even lengths with minimal buffers.
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
- Input string length must be a multiple of 2
- Input string contained non-hexadecimal characters
- Unsupported color hex format.
- The CCITT output buffer is too small for the encoded data.
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, // 79View on GitHub (pinned to 59ce6af6fc)