{"record":{"id":"31ec19d36c3c6315","repo":"apache/dubbo","slug":"bytes2hex-offset-0-offset-is","errorCode":null,"errorMessage":"bytes2hex: offset < 0, offset is {}","messagePattern":"bytes2hex: offset < 0, offset is (.+?)","errorType":"exception","errorClass":"IndexOutOfBoundsException","httpStatus":null,"severity":"error","filePath":"dubbo-common/src/main/java/org/apache/dubbo/common/io/Bytes.java","lineNumber":399,"sourceCode":"     *\n     * @param bs byte array.\n     * @return hex string.\n     */\n    public static String bytes2hex(byte[] bs) {\n        return bytes2hex(bs, 0, bs.length);\n    }\n\n    /**\n     * to hex string.\n     *\n     * @param bs  byte array.\n     * @param off offset.\n     * @param len length.\n     * @return hex string.\n     */\n    public static String bytes2hex(byte[] bs, int off, int len) {\n        if (off < 0) {\n            throw new IndexOutOfBoundsException(\"bytes2hex: offset < 0, offset is \" + off);\n        }\n        if (len < 0) {\n            throw new IndexOutOfBoundsException(\"bytes2hex: length < 0, length is \" + len);\n        }\n        if (off + len > bs.length) {\n            throw new IndexOutOfBoundsException(\"bytes2hex: offset + length > array length.\");\n        }\n\n        byte b;\n        int r = off, w = 0;\n        char[] cs = new char[len * 2];\n        for (int i = 0; i < len; i++) {\n            b = bs[r++];\n            cs[w++] = BASE16[b >> 4 & MASK4];\n            cs[w++] = BASE16[b & MASK4];\n        }\n        return new String(cs);\n    }","sourceCodeStart":381,"sourceCodeEnd":417,"githubUrl":"https://github.com/apache/dubbo/blob/3a3043227f5571d25eb2889de5bca22f2914843b/dubbo-common/src/main/java/org/apache/dubbo/common/io/Bytes.java#L381-L417","documentation":"Thrown by Bytes.bytes2hex(byte[], int, int) when the offset argument is negative. The method converts a region of a byte array to a hexadecimal string; offset must be within [0, array.length]. A negative offset is rejected before any array access as a defensive bounds check to prevent misleading ArrayIndexOutOfBoundsException later.","triggerScenarios":"Calling Bytes.bytes2hex(bs, off, len) with off < 0. Typically off comes from an arithmetic computation, a parsed integer, or a relative index that underflowed or was not range-checked.","commonSituations":"Passing a parsed/decoded offset from a binary protocol parser that produced -1 (sentinel) without checking; off-by-one or sign error in index math; passing a cursor variable that was decremented past zero.","solutions":["Validate offset >= 0 before calling bytes2hex, and clamp or reject invalid input upstream.","If you always want the whole array, use the single-arg overload bytes2hex(byte[]) which sets offset=0, length=array.length.","Check the source of the offset value for sign/underflow bugs."],"exampleFix":"// before\nint off = cursor - step; // may be negative\nString hex = Bytes.bytes2hex(data, off, len); // throws [151]\n\n// after\nif (off < 0 || off + len > data.length) throw new IllegalArgumentException(\"bad range\");\nString hex = Bytes.bytes2hex(data, off, len);","handlingStrategy":"validation","validationCode":"if (off < 0 || len < 0 || off + len > bs.length) {\n    throw new IllegalArgumentException(\"invalid range off=\" + off + \" len=\" + len + \" arr=\" + bs.length);\n}\nString hex = Bytes.bytes2hex(bs, off, len);","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Prefer the single-arg Bytes.bytes2hex(byte[]) overload when encoding the whole array.","Range-check offset/length at the boundary where they are computed or parsed.","Treat -1 sentinels explicitly rather than passing them as offsets."],"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"}