{"record":{"id":"3fdcfb6e553bb4e2","repo":"TooTallNate/Java-WebSocket","slug":"source-array-with-length-d-cannot-have-offset-of","errorCode":null,"errorMessage":"Source array with length %d cannot have offset of %d and still process four bytes.","messagePattern":"Source array with length (.+?) cannot have offset of (.+?) and still process four bytes\\.","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"src/main/java/org/java_websocket/util/Base64.java","lineNumber":814,"sourceCode":"   * @return the number of decoded bytes converted\n   * @throws IllegalArgumentException if source or destination arrays are null, if srcOffset or\n   *                                  destOffset are invalid or there is not enough room in the\n   *                                  array.\n   * @since 1.3\n   */\n  private static int decode4to3(\n      byte[] source, int srcOffset,\n      byte[] destination, int destOffset, int options) {\n\n    // Lots of error checking and exception throwing\n    if (source == null) {\n      throw new IllegalArgumentException(\"Source array was null.\");\n    }   // end if\n    if (destination == null) {\n      throw new IllegalArgumentException(\"Destination array was null.\");\n    }   // end if\n    if (srcOffset < 0 || srcOffset + 3 >= source.length) {\n      throw new IllegalArgumentException(String.format(\n          \"Source array with length %d cannot have offset of %d and still process four bytes.\",\n          source.length, srcOffset));\n    }   // end if\n    if (destOffset < 0 || destOffset + 2 >= destination.length) {\n      throw new IllegalArgumentException(String.format(\n          \"Destination array with length %d cannot have offset of %d and still store three bytes.\",\n          destination.length, destOffset));\n    }   // end if\n\n    final byte[] DECODABET = getDecodabet(options);\n\n    // Example: Dk==\n    if (source[srcOffset + 2] == EQUALS_SIGN) {\n      // Two ways to do the same thing. Don't know which way I like best.\n      //int outBuff =   ( ( DECODABET[ source[ srcOffset    ] ] << 24 ) >>>  6 )\n      //              | ( ( DECODABET[ source[ srcOffset + 1] ] << 24 ) >>> 12 );\n      int outBuff = ((DECODABET[source[srcOffset]] & 0xFF) << 18)\n          | ((DECODABET[source[srcOffset + 1]] & 0xFF) << 12);","sourceCodeStart":796,"sourceCodeEnd":832,"githubUrl":"https://github.com/TooTallNate/Java-WebSocket/blob/afeacbf8c0f6f6a761c9d9daed8c813dd3b8ed7d/src/main/java/org/java_websocket/util/Base64.java#L796-L832","documentation":"decode4to3 must be able to read exactly 4 bytes starting at srcOffset. If srcOffset is negative or srcOffset + 3 >= source.length, fewer than 4 bytes are available and the method throws IllegalArgumentException reporting the source length and offset. The bounds are intentionally strict because the decoder always consumes a full 4-byte quantum.","triggerScenarios":"Calling decode overloads with (source, offset, length/destOffset) where the source slice has fewer than 4 bytes remaining, e.g. decoding a 2-3 byte tail incorrectly or offsetting into a truncated array.","commonSituations":"Manual chunking loops that don't stop at len < 4; decoding truncated Base64 payloads; wrong offset arithmetic when skipping headers/magic bytes.","solutions":["Only call the offset-based decode when srcOffset + 4 <= source.length; handle trailing 2-3 bytes via the standard API.","Use the high-level Base64.decode(String/byte[]) which chunks correctly, instead of manual offset arithmetic.","Validate that the Base64 payload length is a multiple of 4 (after padding) before decoding."],"exampleFix":"// before\nfor (int i = 0; i < src.length; i += 4) {\n    decode4to3(src, i, dest, i / 4 * 3);\n}\n\n// after\nfor (int i = 0; i + 3 < src.length; i += 4) {\n    decode4to3(src, i, dest, i / 4 * 3);\n}","handlingStrategy":"validation","validationCode":"if (src != null && srcOffset >= 0 && srcOffset + 4 <= src.length) {\n    decode4to3(src, srcOffset, dest, destOffset);\n}","typeGuard":"static boolean canReadFourBytes(byte[] a, int off) {\n    return a != null && off >= 0 && off + 4 <= a.length;\n}","tryCatchPattern":"try {\n    Base64.decode(src, off, len, dest, destOff);\n} catch (IllegalArgumentException e) {\n    // source slice too small — fall back to full decode\n    decoded = Base64.decode(src);\n}","preventionTips":["Loop with condition i + 3 < src.length when chunking in 4-byte quanta.","Validate that Base64 input length (after padding) is a multiple of 4.","Prefer Base64.decode(byte[]) over manual offset-based decoding."],"tags":["java","base64","out-of-bounds","offset"],"backgroundTag":"argument-out-of-range","analyzedSha":"afeacbf8c0f6f6a761c9d9daed8c813dd3b8ed7d","analyzedAt":"2026-09-09T14:39:47.546Z","contentChangedAt":"2026-09-09T14:39:47.546Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}