hibernate/hibernate-orm · error · HibernateException
IOException occurred reading a binary value
Error message
IOException occurred reading a binary value
What it means
Thrown by BlobJavaType.unwrap when a raw (non-BlobImplementer) Blob is converted to byte[]: it calls value.getBinaryStream().readAllBytes() and an IOException during the read is wrapped in HibernateException('IOException occurred reading a binary value'). Unlike the SQLException variants, this means the stream opened but broke mid-read: connection dropped, stream closed underneath, or the driver could not deliver the full LOB payload.
Source
Thrown at hibernate-core/src/main/java/org/hibernate/type/descriptor/java/BlobJavaType.java:137
return null;
}
try {
if ( Blob.class.isAssignableFrom( type ) ) {
return type.cast( options.getLobCreator().toJdbcBlob( value ) );
}
else if ( byte[].class.isAssignableFrom( type )) {
if (value instanceof BlobImplementer blobImplementer) {
// if the incoming Blob is a wrapper, just grab the bytes from its BinaryStream
return type.cast( blobImplementer.getUnderlyingStream().getBytes() );
}
else {
try {
// otherwise extract the bytes from the stream manually
return type.cast( value.getBinaryStream().readAllBytes() );
}
catch ( IOException e ) {
throw new HibernateException( "IOException occurred reading a binary value", e );
}
}
}
else if ( BinaryStream.class.isAssignableFrom( type ) ) {
if (value instanceof BlobImplementer blobImplementer) {
return type.cast( blobImplementer.getUnderlyingStream() );
}
else {
return type.cast( new StreamBackedBinaryStream( value.getBinaryStream(), value.length() ) );
}
}
else if ( InputStream.class.isAssignableFrom( type ) ) {
if (value instanceof BlobImplementer blobImplementer) {
// if the incoming Blob is a wrapper, just pass along its BinaryStream
return type.cast( blobImplementer.getUnderlyingStream().getInputStream() );
}
else {
// otherwise we need to build a BinaryStream...View on GitHub (pinned to fad1729dce)
Solutions
- Keep the session/transaction open until the byte[] has been fully read.
- Raise driver/pool timeouts (socketTimeout, connection idle timeout) for connections that stream large LOBs.
- Map byte[] directly with @Lob so Hibernate materializes the value during the row read.
- If the connection was invalidated, retry the load once on a fresh session.
Example fix
// before @Lob private java.sql.Blob data; byte[] bytes = entity.getData().getBinaryStream().readAllBytes(); // after tx -> IOException // after @Lob private byte[] data; // materialized eagerly by Hibernate byte[] bytes = entity.getData();
Defensive patterns
Strategy: retry
Validate before calling
// fail fast if the connection is already suspect
if (!connection.isValid(2)) throw new IllegalStateException("Connection unhealthy; reload instead of streaming LOB"); Try / catch
try {
bytes = blob.getBinaryStream().readAllBytes();
} catch (IOException | HibernateException e) {
// stream broke mid-read: one retry on a fresh session is usually enough
return retryInNewSession(id);
} Prevention
- Size socket/pool timeouts above your largest LOB transfer time.
- Read LOB columns in the same statement/transaction as the load.
- Stream very large BLOBs chunked instead of readAllBytes in one shot.
When it happens
Trigger: unwrap(..., byte[].class) on a plain JDBC Blob (loading a byte[] attribute from a BLOB column without Hibernate's wrapper); reading a large BLOB when the socket times out or the connection is invalidated mid-stream; reading the stream after it was already consumed or the statement was closed.
Common situations: Large binary columns (documents, images) exceeding socket/driver buffer or timeout settings; pool eviction (idle-in-transaction) while streaming a LOB; load-after-commit access patterns.
Related errors
- Unable to set BLOB bytes after creation
- Could not create JDBC Blob
- Start position 1-based; must be 1 or more.
- Length must be great-than-or-equal to zero.
- Start position [<start>] cannot exceed overall CLOB length [
AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22).
Data as JSON: /api/errors/1ddb49759c26339b.
Report an issue: GitHub.