SixLabors/ImageSharp · error · ArgumentException
Input string length must be a multiple of 2
Error message
Input string length must be a multiple of 2
What it means
HexConverter.HexStringToBytes parses a hex string into bytes and requires the character span length to be even, since every output byte consumes exactly two hex characters. An odd-length input cannot be parsed unambiguously, so an ArgumentException naming the 'chars' parameter is thrown.
Solutions
- Validate/normalize the hex string to an even length before calling (pad a leading 0 or reject the input).
- Fix the slicing logic that produced the odd-length span.
- Catch ArgumentException and report a user-facing invalid-hex-format error.
Example fix
// before
HexConverter.HexStringToBytes("A1B2C".AsSpan(), dest);
// after
var hex = "A1B2C";
if (hex.Length % 2 != 0) hex = "0" + hex; // or throw InvalidDataException
HexConverter.HexStringToBytes(hex.AsSpan(), dest); Defensive patterns
Strategy: validation
Validate before calling
if (hex.Length == 0 || hex.Length % 2 != 0)
throw new FormatException($"Hex string must have an even length, got {hex.Length}."); Type guard
static bool IsEvenLengthHex(ReadOnlySpan<char> s) => s.Length % 2 == 0;
Try / catch
try { written = HexConverter.HexStringToBytes(hex.AsSpan(), dest); }
catch (ArgumentException ex) { throw new FormatException("Invalid hex string length.", ex); } Prevention
- Validate even length and hex charset before calling.
- Fix string-slicing boundaries that can chop a hex pair.
- Prefer Convert.FromHexString for untrusted user input to get clearer errors.
When it happens
Trigger: Calling HexStringToBytes with a ReadOnlySpan<char> whose Length is odd, e.g. "ABC" or a truncated hex literal produced by string slicing.
Common situations: Hand-copied hex color/identifier strings with a dropped digit; parsing concatenated hex tokens where one is truncated; off-by-one substring offsets.
Understand the failure class
Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.
Related errors
- Output span must be at least half the length of the input…
- Input string contained non-hexadecimal characters
- Input string is not in the correct format.
- Unsupported color hex format.
- The BigTIFF directory entry count exceeds the available…
AI-assisted analysis of SixLabors/ImageSharp@59ce6af6fc (2026-09-13).
Data as JSON: /api/errors/a8659a188d8874d9.
Report an issue: GitHub.
Appendix: source
Thrown at src/ImageSharp/Common/Helpers/HexConverter.cs:21
using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.Common.Helpers;
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 =
[View on GitHub (pinned to 59ce6af6fc)