{"record":{"id":"3315257157e9355c","repo":"apache/dubbo","slug":"hex2bytes-offset-length-array-length","errorCode":null,"errorMessage":"hex2bytes: offset + length > array length.","messagePattern":"hex2bytes: offset \\+ length > array length\\.","errorType":"exception","errorClass":"IndexOutOfBoundsException","httpStatus":null,"severity":"error","filePath":"dubbo-common/src/main/java/org/apache/dubbo/common/io/Bytes.java","lineNumber":449,"sourceCode":"     *\n     * @param str hex string.\n     * @param off offset.\n     * @param len length.\n     * @return byte array.\n     */\n    public static byte[] hex2bytes(final String str, final int off, int len) {\n        if ((len & 1) == 1) {\n            throw new IllegalArgumentException(\"hex2bytes: ( len & 1 ) == 1.\");\n        }\n\n        if (off < 0) {\n            throw new IndexOutOfBoundsException(\"hex2bytes: offset < 0, offset is \" + off);\n        }\n        if (len < 0) {\n            throw new IndexOutOfBoundsException(\"hex2bytes: length < 0, length is \" + len);\n        }\n        if (off + len > str.length()) {\n            throw new IndexOutOfBoundsException(\"hex2bytes: offset + length > array length.\");\n        }\n\n        int num = len / 2, r = off, w = 0;\n        byte[] b = new byte[num];\n        for (int i = 0; i < num; i++) {\n            b[w++] = (byte) (hex(str.charAt(r++)) << 4 | hex(str.charAt(r++)));\n        }\n        return b;\n    }\n\n    /**\n     * to base64 string.\n     *\n     * @param b byte array.\n     * @return base64 string.\n     */\n    public static String bytes2base64(byte[] b) {\n        return bytes2base64(b, 0, b.length, BASE64);","sourceCodeStart":431,"sourceCodeEnd":467,"githubUrl":"https://github.com/apache/dubbo/blob/3a3043227f5571d25eb2889de5bca22f2914843b/dubbo-common/src/main/java/org/apache/dubbo/common/io/Bytes.java#L431-L467","documentation":"Thrown by Bytes.hex2bytes(String, int, int) when off + len exceeds the source string length. This upper-bound check ensures the requested character region [off, off+len) lies within the string, preventing StringIndexOutOfBoundsException during charAt reads in the conversion loop. It is the last of the four hex2bytes validations.","triggerScenarios":"Calling Bytes.hex2bytes(str, off, len) where off + len > str.length(). Usually a stale length computed against a longer string, or a substring that was trimmed but the old length retained.","commonSituations":"Truncating a hex string but keeping the original length; off-by-one including the null terminator or delimiter in len; concatenation/removal that changed string size after length was computed.","solutions":["Recompute len against the actual string length: len = Math.min(len, str.length() - off).","Use hex2bytes(String) for the whole string.","Ensure the string and its computed region are derived from the same source."],"exampleFix":"// before\nString hex = fullHex.substring(0, 10);\nbyte[] b = Bytes.hex2bytes(hex, 0, fullHex.length()); // throws [157]\n\n// after\nbyte[] b = Bytes.hex2bytes(hex, 0, hex.length());","handlingStrategy":"validation","validationCode":"if (off + len > str.length()) len = str.length() - off; // clamp\nbyte[] b = Bytes.hex2bytes(str, off, len);","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Recompute len against the actual string length after truncation.","Use hex2bytes(String) for the whole string.","Ensure the string and its region come from the same source."],"tags":["bytes","hex","bounds-check","validation"],"backgroundTag":null,"analyzedSha":"3a3043227f5571d25eb2889de5bca22f2914843b","analyzedAt":"2026-08-14T00:43:19.853Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}