hibernate/hibernate-orm · error · SQLException

Can't deal with Clobs larger than 'Integer.MAX_VALUE'

Error message

Can't deal with Clobs larger than 'Integer.MAX_VALUE'

What it means

ClobProxy.getCharacterStream(long start, long length) can only window a region that fits an int, because it casts length to int for DataHelper.subStream. A length above Integer.MAX_VALUE characters is rejected with this SQLException instead of being truncated.

Source

Thrown at hibernate-core/src/main/java/org/hibernate/engine/jdbc/proxy/ClobProxy.java:148

		}
		if ( length < 0 ) {
			throw new SQLException( "Length must be great-than-or-equal to zero." );
		}
		final String string = characterStream.asString();
		final long endIndex = Math.min( start + length - 1, string.length() );
		return string.substring( (int) start - 1, (int) endIndex );
	}

	@Override
	public Reader getCharacterStream(long start, long length) throws SQLException {
		if ( start < 1 ) {
			throw new SQLException( "Start position 1-based; must be 1 or more." );
		}
		if ( start > length() + 1 ) {
			throw new SQLException( "Start position [" + start + "] cannot exceed overall CLOB length [" + length() + "]" );
		}
		if ( length > Integer.MAX_VALUE ) {
			throw new SQLException( "Can't deal with Clobs larger than 'Integer.MAX_VALUE'" );
		}
		if ( length < 0 ) {
			// javadoc for getCharacterStream(long,int) specifies that the start+length must not exceed the
			// total length (this is at odds with the behavior of getSubString(long,int))
			throw new SQLException( "Length must be greater than or equal to zero" );
		}
		return DataHelper.subStream( getCharacterStream(), start-1, (int) length );
	}

	@Override
	public void free() throws SQLException {
		characterStream.release();
	}

	protected void resetIfNeeded() {
		try {
			if ( needsReset ) {
				characterStream.asReader().reset();

View on GitHub (pinned to fad1729dce)

Solutions

  1. Read in chunks with length capped well below Integer.MAX_VALUE (e.g. 64K)
  2. Use getCharacterStream() (no args) and stream-copy for whole-content reads
  3. Replace sentinel sizes with the actual remaining character count

Example fix

// before
Reader all = clob.getCharacterStream(1, Long.MAX_VALUE); // throws

// after
Reader all = clob.getCharacterStream(); // full reader, copy incrementally
Defensive patterns

Strategy: validation

Validate before calling

static final long MAX_CHARS = 64L * 1024;        // 64K characters per window
static long capLength(long requested, long remaining) {
    if (requested < 0) throw new IllegalArgumentException("length must be >= 0");
    return Math.min(Math.min(requested, remaining), MAX_CHARS);
}
// usage: clob.getCharacterStream(start, capLength(len, clob.length() - start + 1))

Try / catch

try {
    r = clob.getCharacterStream(start, length);
} catch (SQLException e) {
    if (e.getMessage() != null && e.getMessage().contains("Integer.MAX_VALUE")) {
        r = clob.getCharacterStream();              // fall back to the full reader
    } else {
        throw e;
    }
}

Prevention

When it happens

Trigger: Calling clob.getCharacterStream(1, clob.length()) on a Clob longer than Integer.MAX_VALUE characters; passing Long.MAX_VALUE as an 'until the end' marker; forwarding a long limit from a framework streaming API.

Common situations: Very large text stores (document archives, logs) held as CLOBs; 'read all' helpers that use a huge sentinel; migration from drivers that silently clamp to Hibernate's fail-fast proxy.

Related errors


AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22). Data as JSON: /api/errors/97ada15ecfe97991. Report an issue: GitHub.