hibernate/hibernate-orm · error · HibernateException
Unable to skip needed bytes
Error message
Unable to skip needed bytes
What it means
In the substring variant extractString(Reader characterStream, long start, int length), Hibernate first positions the stream with characterStream.skip(start); if the reader reports skipping fewer characters than requested, it throws HibernateException('Unable to skip needed bytes') before reading anything. It fires when the LOB reader cannot seek — usually because the stream is shorter than start or the driver's skip() is not fully conformant.
Source
Thrown at hibernate-core/src/main/java/org/hibernate/type/descriptor/java/DataHelper.java:103
/**
* Extracts a portion of the contents of the given reader/stream as a string.
*
* @param characterStream The reader for the content
* @param start The start position/offset (0-based, per general stream/reader contracts).
* @param length The amount to extract
*
* @return The content as string
*/
private static String extractString(Reader characterStream, long start, int length) {
if ( length == 0 ) {
return "";
}
final var stringBuilder = new StringBuilder( length );
try {
final long skipped = characterStream.skip( start );
if ( skipped != start ) {
throw new HibernateException( "Unable to skip needed bytes" );
}
final int bufferSize = getSuggestedBufferSize( length );
final char[] buffer = new char[bufferSize];
int charsRead = 0;
while ( true ) {
final int amountRead = characterStream.read( buffer, 0, bufferSize );
if ( amountRead == -1 ) {
break;
}
stringBuilder.append( buffer, 0, amountRead );
if ( amountRead < bufferSize ) {
// we have read up to the end of stream
break;
}
charsRead += amountRead;
if ( charsRead >= length ) {
break;
}View on GitHub (pinned to fad1729dce)
Solutions
- Validate offsets against Clob.length() before extraction and clamp start to the actual length
- Upgrade the JDBC driver — skip() conformance bugs are a known driver issue
- Avoid partial reads: read the whole CLOB and substring in Java via Clob.getSubString
- Re-read the row in a fresh transaction if the LOB can change concurrently
Example fix
// before Reader r = clob.getCharacterStream(); String part = extractBySkip(r, 500, 100); // may fail: skipped != 500 // after String all = clob.getSubString(1, (int) clob.length()); String part = all.substring(500, Math.min(600, all.length()));
Defensive patterns
Strategy: validation
Validate before calling
long len = clob.length();
if (start < 0 || start >= len) {
throw new IllegalArgumentException("start " + start + " outside LOB length " + len);
} Prevention
- Always bound start/length by Clob.length() before extraction
- Prefer full reads plus in-memory substring over stream skipping
- Pin a recent JDBC driver — skip() conformance varies
When it happens
Trigger: Partial CLOB extraction (the start/length paths) where the character stream ends before start; a driver Reader whose skip() legitimately returns less than n; start offsets computed from stale length metadata.
Common situations: Concurrent truncation of the row's LOB between length computation and read; locator-based LOBs on drivers with weak skip support; offsets derived from a previous read of the row.
Related errors
- IOException occurred reading text
- Unable to set CLOB string after creation
- Could not create JDBC Clob
- Underlying stream does not allow reset
- Start position 1-based; must be 1 or more.
AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22).
Data as JSON: /api/errors/f4152828552e569a.
Report an issue: GitHub.