TooTallNate/Java-WebSocket · error · IllegalArgumentException
Source array with length
Error message
Source array with length %d cannot have offset of %d and still process four bytes.
What it means
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.
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.
Example fix
// before
for (int i = 0; i < src.length; i += 4) {
decode4to3(src, i, dest, i / 4 * 3);
}
// after
for (int i = 0; i + 3 < src.length; i += 4) {
decode4to3(src, i, dest, i / 4 * 3);
} Defensive patterns
Strategy: validation
Validate before calling
if (src != null && srcOffset >= 0 && srcOffset + 4 <= src.length) {
decode4to3(src, srcOffset, dest, destOffset);
} Type guard
static boolean canReadFourBytes(byte[] a, int off) {
return a != null && off >= 0 && off + 4 <= a.length;
} Try / catch
try {
Base64.decode(src, off, len, dest, destOff);
} catch (IllegalArgumentException e) {
// source slice too small — fall back to full decode
decoded = Base64.decode(src);
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: Manual chunking loops that don't stop at len < 4; decoding truncated Base64 payloads; wrong offset arithmetic when skipping headers/magic bytes.
Related errors
- Cannot have offset of
- Destination array with length
- Cannot have length offset:
- Source array was null.
- Destination array was null.
AI-assisted analysis of TooTallNate/Java-WebSocket@afeacbf8c0 (2026-09-09).
Data as JSON: /api/errors/3fdcfb6e553bb4e2.
Report an issue: GitHub.
Appendix: source
Thrown at src/main/java/org/java_websocket/util/Base64.java:814
* @return the number of decoded bytes converted
* @throws IllegalArgumentException if source or destination arrays are null, if srcOffset or
* destOffset are invalid or there is not enough room in the
* array.
* @since 1.3
*/
private static int decode4to3(
byte[] source, int srcOffset,
byte[] destination, int destOffset, int options) {
// Lots of error checking and exception throwing
if (source == null) {
throw new IllegalArgumentException("Source array was null.");
} // end if
if (destination == null) {
throw new IllegalArgumentException("Destination array was null.");
} // end if
if (srcOffset < 0 || srcOffset + 3 >= source.length) {
throw new IllegalArgumentException(String.format(
"Source array with length %d cannot have offset of %d and still process four bytes.",
source.length, srcOffset));
} // end if
if (destOffset < 0 || destOffset + 2 >= destination.length) {
throw new IllegalArgumentException(String.format(
"Destination array with length %d cannot have offset of %d and still store three bytes.",
destination.length, destOffset));
} // end if
final byte[] DECODABET = getDecodabet(options);
// Example: Dk==
if (source[srcOffset + 2] == EQUALS_SIGN) {
// Two ways to do the same thing. Don't know which way I like best.
//int outBuff = ( ( DECODABET[ source[ srcOffset ] ] << 24 ) >>> 6 )
// | ( ( DECODABET[ source[ srcOffset + 1] ] << 24 ) >>> 12 );
int outBuff = ((DECODABET[source[srcOffset]] & 0xFF) << 18)
| ((DECODABET[source[srcOffset + 1]] & 0xFF) << 12);View on GitHub (pinned to afeacbf8c0)