chinabugotech/hutool · error · IndexOutOfBoundsException

Position is out of maxLength: {}

Error message

Position is out of maxLength: {}

What it means

BufferUtil.lineEnd(buffer, maxLength) scans a ByteBuffer byte-by-byte for a CR/LF line terminator. If the scan travels more than maxLength bytes from the start position without finding a newline, it resets the buffer position and throws IndexOutOfBoundsException to prevent unbounded scanning.

Source

Thrown at hutool-core/src/main/java/cn/hutool/core/io/BufferUtil.java:182

		boolean canEnd = false;
		int charIndex = primitivePosition;
		byte b;
		while (buffer.hasRemaining()) {
			b = buffer.get();
			charIndex++;
			if (b == StrUtil.C_CR) {
				canEnd = true;
			} else if (b == StrUtil.C_LF) {
				return canEnd ? charIndex - 2 : charIndex - 1;
			} else {
				// 只有\r无法确认换行
				canEnd = false;
			}

			if (charIndex - primitivePosition > maxLength) {
				// 查找到尽头,未找到,还原位置
				buffer.position(primitivePosition);
				throw new IndexOutOfBoundsException(StrUtil.format("Position is out of maxLength: {}", maxLength));
			}
		}

		// 查找到buffer尽头,未找到,还原位置
		buffer.position(primitivePosition);
		// 读到结束位置
		return -1;
	}

	/**
	 * 读取一行,如果buffer中最后一部分并非完整一行,则返回null<br>
	 * 支持的换行符如下:
	 *
	 * <pre>
	 * 1. \r\n
	 * 2. \n
	 * </pre>
	 *

View on GitHub (pinned to 8870454b2a)

Solutions

  1. Increase maxLength to at least the longest expected line length.
  2. Use the no-arg lineEnd(buffer) overload which defaults maxLength to buffer.remaining() and scans to buffer end (returns -1 instead of throwing).
  3. Pre-split or chunk input so individual line scans stay within the bound.

Example fix

// before: throws when a line exceeds 1024 bytes
int end = BufferUtil.lineEnd(buf, 1024);

// after: scan the whole remaining buffer, no bound error
int end = BufferUtil.lineEnd(buf);
// or size the bound to real data
int end = BufferUtil.lineEnd(buf, buf.remaining());
Defensive patterns

Strategy: validation

Validate before calling

int remaining = buffer.remaining();
// if you cannot guarantee a line fits, scan the whole buffer instead:
int end = BufferUtil.lineEnd(buffer); // returns -1 instead of throwing
// or size the bound to the data:
// int end = BufferUtil.lineEnd(buffer, remaining);

Try / catch

try {
    int end = BufferUtil.lineEnd(buf, maxLength);
} catch (IndexOutOfBoundsException e) {
    // no newline within maxLength: buf position was reset; treat as one long line or expand bound
}

Prevention

When it happens

Trigger: Calling BufferUtil.lineEnd(buffer, maxLength) when the data from the current position to the next newline (or end of buffer) exceeds maxLength bytes.

Common situations: Processing minified JS/base64 blobs/log lines with very long lines using a maxLength that is too small; reading binary data containing no line terminators; reusing a small maxLength copied from a sample that didn't have long lines.

Related errors


AI-assisted analysis of chinabugotech/hutool@8870454b2a (2026-08-14). Data as JSON: /api/errors/ee5184353da6f73d. Report an issue: GitHub.