hibernate/hibernate-orm · error · HibernateException
Unable to access clob stream
Error message
Unable to access clob stream
What it means
ClobJavaType.unwrap wraps any SQLException raised while calling getCharacterStream()/length() during Clob to String/Reader/CharacterStream conversions into HibernateException('Unable to access clob stream'). It is the character-LOB twin of the blob-stream error: the locator is dead or the driver refused the operation.
Source
Thrown at hibernate-core/src/main/java/org/hibernate/type/descriptor/java/ClobJavaType.java:131
}
else {
// otherwise we need to build a CharacterStream...
return type.cast( value.getCharacterStream() );
}
}
else if ( CharacterStream.class.isAssignableFrom( type ) ) {
if (value instanceof ClobImplementer clobImplementer) {
// if the incoming Clob is a wrapper, just pass along its CharacterStream
return type.cast( clobImplementer.getUnderlyingStream() );
}
else {
// otherwise we need to build a CharacterStream...
return type.cast( new CharacterStreamImpl( value.getCharacterStream(), value.length() ) );
}
}
}
catch ( SQLException e ) {
throw new HibernateException( "Unable to access clob stream", e );
}
throw unknownUnwrap( type );
}
public <X> Clob wrap(X value, WrapperOptions options) {
if ( value == null ) {
return null;
}
else {
final LobCreator lobCreator = options.getLobCreator();
if ( value instanceof Clob clob ) {
return lobCreator.wrap( clob );
}
else if ( value instanceof String string ) {
return lobCreator.createClob( string );
}
else if ( value instanceof Reader reader ) {View on GitHub (pinned to fad1729dce)
Solutions
- Convert the Clob to String inside the transaction that loaded it.
- Map the attribute as String with @Lob instead of java.sql.Clob.
- Re-fetch the entity in a fresh session before any conversion.
Example fix
// before Clob clob = detachedItem.getText(); String text = clob.getSubString(1, (int) clob.length()); // after tx -> wrapped SQLException // after @Lob private String text; // materialized by Hibernate during read String value = item.getText();
Defensive patterns
Strategy: try-catch
Validate before calling
try {
clob.length(); // probe locator liveness before unwrap
} catch (SQLException e) {
throw new IllegalStateException("Clob locator is dead; re-load the entity", e);
} Try / catch
try {
return clobJavaType.unwrap(clob, String.class, options);
} catch (HibernateException e) {
if (e.getCause() instanceof SQLException) {
return reloadAndGetText(id); // fresh session inside a live tx
}
throw e;
} Prevention
- Map @Lob String instead of java.sql.Clob unless streaming is required.
- Materialize CLOB text inside the loading transaction.
- Do not let entities with Clob handles become detached.
When it happens
Trigger: Unwrapping a raw java.sql.Clob to String/Reader after its transaction or connection ended; converting a detached entity's Clob field; consuming a Clob returned by a stored function after the call completed.
Common situations: Post-commit access to Clob attributes; Oracle temporary CLOBs freed at commit; connection-pool recycling during long reads; OSIV disabled in web apps.
Related errors
- Unable to set CLOB string after creation
- Could not create JDBC Clob
- Start position 1-based; must be 1 or more.
- Start position [${start}] cannot exceed overall CLOB length
- 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/05f08d1381449807.
Report an issue: GitHub.