hibernate/hibernate-orm · error · HibernateException

IOException occurred reading text

Error message

IOException occurred reading text

What it means

DataHelper.extractString(Reader) slurps a whole java.io.Reader (typically the character stream of a CLOB or long text column) into a String; any IOException from reader.read is rethrown as HibernateException('IOException occurred reading text'). The reader is closed in a finally block and close failures are only logged via CORE_LOGGER.unableToCloseStream, so the exception you see is always the read failure itself.

Source

Thrown at hibernate-core/src/main/java/org/hibernate/type/descriptor/java/DataHelper.java:73

	 *
	 * @return The content as string
	 */
	public static String extractString(Reader reader, int lengthHint) {
		// read the Reader contents into a buffer and return the complete string
		final int bufferSize = getSuggestedBufferSize( lengthHint );
		final var stringBuilder = new StringBuilder( bufferSize );
		try {
			final char[] buffer = new char[bufferSize];
			while (true) {
				int amountRead = reader.read( buffer, 0, bufferSize );
				if ( amountRead == -1 ) {
					break;
				}
				stringBuilder.append( buffer, 0, amountRead );
			}
		}
		catch ( IOException ioe ) {
			throw new HibernateException( "IOException occurred reading text", ioe );
		}
		finally {
			try {
				reader.close();
			}
			catch (IOException e) {
				CORE_LOGGER.unableToCloseStream( e );
			}
		}
		return stringBuilder.toString();
	}

	/**
	 * 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

View on GitHub (pinned to fad1729dce)

Solutions

  1. Read LOB properties while the Session and transaction are still open — force initialization before commit
  2. If lazy LOBs are intended, configure bytecode enhancement correctly, or drop lazy loading on large text columns
  3. Catch HibernateException and inspect getCause() for the IOException type (SocketTimeoutException vs StreamClosed vs SocketException) and fix the underlying transport/timeout issue
  4. For very large values, stream to disk or object storage instead of materializing a String

Example fix

// before
tx.commit(); session.close();
String body = entity.getBody(); // lazy @Lob read after close -> IOException

// after
String body = entity.getBody(); // materialize inside the transaction
tx.commit(); session.close();
Defensive patterns

Strategy: try-catch

Try / catch

try {
    String body = entity.getBody(); // lazy @Lob materialization
} catch (HibernateException e) {
    if (e.getCause() instanceof IOException ioe) {
        // transport or stream-lifetime problem: reopen session, retry once
    }
}

Prevention

When it happens

Trigger: Materializing a @Lob String / Clob / materialized_clob attribute when the stream breaks mid-read: the database connection was dropped or timed out, the LOB was freed by the driver, or the stream was already closed because the Session or transaction ended before the read.

Common situations: Touching a lazy LOB getter after session.close() or commit (classic lazy-LOB trap); long CLOB reads hitting socket timeouts; DB failover or network resets during large reads.

Related errors


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