hibernate/hibernate-orm · error · HibernateException
Unable to access blob stream
Error message
Unable to access blob stream
What it means
Thrown by BlobJavaType.toString(Blob) when Hibernate materializes a java.sql.Blob into its string form. The method opens value.getBinaryStream() and fully reads it via DataHelper.extractBytes; any SQLException from the driver (invalid or freed locator, closed connection, driver limit) is wrapped in HibernateException with this message. Blob locators are only valid while the connection/transaction that produced them is still alive.
Source
Thrown at hibernate-core/src/main/java/org/hibernate/type/descriptor/java/BlobJavaType.java:90
@Override
public Blob cast(Object value) {
return (Blob) value;
}
@Override
public String extractLoggableRepresentation(Blob value) {
return value == null ? "null" : "{blob}";
}
@Override
public String toString(Blob value) {
final byte[] bytes;
try {
bytes = extractBytes( value.getBinaryStream() );
}
catch ( SQLException e ) {
throw new HibernateException( "Unable to access blob stream", e );
}
return PrimitiveByteArrayJavaType.INSTANCE.toString( bytes );
}
@Override
public Blob fromString(CharSequence string) {
return BlobProxy.generateProxy( PrimitiveByteArrayJavaType.INSTANCE.fromString( string ) );
}
@Override
public int extractHashCode(Blob value) {
return System.identityHashCode( value );
}
@Override
public boolean areEqual(Blob one, Blob another) {
return one == another;
}View on GitHub (pinned to fad1729dce)
Solutions
- Exclude Blob attributes from toString()/logging; never stringify live LOB handles.
- Map the attribute as byte[] with @Lob instead of java.sql.Blob so the data is materialized eagerly at read time.
- Access and convert the Blob inside the same open session/transaction that loaded it.
- If the stream was consumed, re-query the entity in a fresh session before converting.
Example fix
// before
@Lob @Basic(fetch = FetchType.LAZY)
private java.sql.Blob data;
log.info("loaded {}", entity); // toString() touches the Blob -> HibernateException
// after
@Lob
private byte[] data; // materialized during row read
log.info("loaded {} bytes", entity.getData().length); Defensive patterns
Strategy: try-catch
Validate before calling
// only convert while the session that loaded the Blob is alive
if (!session.isOpen() || !session.isConnected()) {
throw new IllegalStateException("Reload the entity in an open session before touching the Blob");
} Try / catch
try {
return PrimitiveByteArrayJavaType.INSTANCE.toString(extractBytes(blob.getBinaryStream()));
} catch (HibernateException e) {
if (e.getCause() instanceof SQLException) {
// locator died: re-load in a fresh transaction or surface a domain error
throw new IllegalStateException("Blob for entity " + id + " is no longer readable", e);
}
throw e;
} Prevention
- Never include java.sql.Blob fields in toString()/equals()/log output.
- Prefer byte[] + @Lob mappings unless streaming is required.
- Materialize LOB content inside the loading transaction; never after commit.
- Keep LOB-touching code off lazy-init paths that can run post-session.
When it happens
Trigger: Calling toString()/logging on a detached entity that holds a Blob attribute; dirty-check or TRACE logging that stringifies the Blob; converting a Blob-typed query result to String after the transaction committed; Oracle freeing a temporary LOB on commit, or the stream already having been consumed once.
Common situations: Entities with java.sql.Blob @Lob fields included in toString()/log statements; access after the session closed (OSIV disabled); batch jobs carrying entities across transactions; driver-specific LOB lifetime quirks (Oracle temp LOBs, PostgreSQL Large Objects).
Related errors
- Unable to set BLOB bytes after creation
- Could not create JDBC Blob
- Underlying stream does not allow reset
- Start position 1-based; must be 1 or more.
- Length must be great-than-or-equal to zero.
AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22).
Data as JSON: /api/errors/ab8d4407d5e0c6e0.
Report an issue: GitHub.