{"record":{"id":"a77aad60561a0d18","repo":"SixLabors/ImageSharp","slug":"output-span-must-be-at-least-half-the-length-of-the-input","errorCode":null,"errorMessage":"Output span must be at least half the length of the input string","messagePattern":"Output span must be at least half the length of the input string","errorType":"exception","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"src/ImageSharp/Common/Helpers/HexConverter.cs","lineNumber":26,"sourceCode":"internal static class HexConverter\n{\n    /// <summary>\n    /// Parses a hexadecimal string into a byte array without allocations. Throws on non-hexadecimal character.\n    /// Adapted from https://source.dot.net/#System.Private.CoreLib/Convert.cs,c9e4fbeaca708991.\n    /// </summary>\n    /// <param name=\"chars\">The hexadecimal string to parse.</param>\n    /// <param name=\"bytes\">The destination for the parsed bytes. Must be at least <paramref name=\"chars\"/>.Length / 2 bytes long.</param>\n    /// <returns>The number of bytes written to <paramref name=\"bytes\"/>.</returns>\n    public static int HexStringToBytes(ReadOnlySpan<char> chars, Span<byte> bytes)\n    {\n        if (Numerics.Modulo2(chars.Length) != 0)\n        {\n            throw new ArgumentException(\"Input string length must be a multiple of 2\", nameof(chars));\n        }\n\n        if ((bytes.Length << 1 /* bit-hack for *2 */) < chars.Length)\n        {\n            throw new ArgumentException(\"Output span must be at least half the length of the input string\");\n        }\n\n        // Slightly better performance in the loop below, allows us to skip a bounds check\n        // while still supporting output buffers that are larger than necessary\n        bytes = bytes[..(chars.Length >> 1)];   // bit-hack for / 2\n\n        [MethodImpl(MethodImplOptions.AggressiveInlining)]\n        static int FromChar(int c)\n        {\n            // Map from an ASCII char to its hex value, e.g. arr['b'] == 11. 0xFF means it's not a hex digit.\n            // This doesn't actually allocate.\n            ReadOnlySpan<byte> charToHexLookup =\n            [\n                0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 15\n                0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 31\n                0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 47\n                0x0,  0x1,  0x2,  0x3,  0x4,  0x5,  0x6,  0x7,  0x8,  0x9,  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 63\n                0xFF, 0xA,  0xB,  0xC,  0xD,  0xE,  0xF,  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 79","sourceCodeStart":8,"sourceCodeEnd":44,"githubUrl":"https://github.com/SixLabors/ImageSharp/blob/59ce6af6fc29027cda277ef62d4d1694a8acce91/src/ImageSharp/Common/Helpers/HexConverter.cs#L8-L44","documentation":"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.","triggerScenarios":"Calling HexStringToBytes(chars, bytes) where bytes.Length < chars.Length / 2, e.g. allocating Convert.FromHexString-style output from an incorrect length formula.","commonSituations":"Allocating the destination with chars.Length instead of (chars.Length + 1) / 2; reusing a smaller buffer across calls; misreading the API's length contract.","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."],"exampleFix":"// before\nbyte[] dest = new byte[hex.Length / 3];\nHexConverter.HexStringToBytes(hex.AsSpan(), dest);\n// after\nbyte[] dest = new byte[hex.Length / 2];\nint written = HexConverter.HexStringToBytes(hex.AsSpan(), dest);","handlingStrategy":"validation","validationCode":"byte[] dest = new byte[hex.Length / 2];\nDebug.Assert(dest.Length << 1 >= hex.Length);","typeGuard":null,"tryCatchPattern":"try { written = HexConverter.HexStringToBytes(chars, dest); }\ncatch (ArgumentException ex) when (ex.ParamName == nameof(dest))\n{ dest = new byte[chars.Length / 2]; written = HexConverter.HexStringToBytes(chars, dest); }","preventionTips":["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."],"tags":["hex","argument-exception","buffer-size","helpers"],"backgroundTag":"argument-out-of-range","analyzedSha":"59ce6af6fc29027cda277ef62d4d1694a8acce91","analyzedAt":"2026-09-13T18:34:59.331Z","contentChangedAt":"2026-09-13T18:34:59.331Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}