hibernate/hibernate-orm · error · HibernateException

IOException occurred reading a binary value

Error message

IOException occurred reading a binary value

What it means

StreamBackedBinaryStream.getBytes() lazily materializes the wrapped InputStream with readAllBytes() the first time the byte[] is needed (e.g. when binding a stream-backed Blob to a statement). An IOException during that read is wrapped in HibernateException('IOException occurred reading a binary value').

Source

Thrown at hibernate-core/src/main/java/org/hibernate/engine/jdbc/internal/StreamBackedBinaryStream.java:43

	public StreamBackedBinaryStream(InputStream stream, long length) {
		this.stream = stream;
		this.length = length;
	}

	@Override
	public InputStream getInputStream() {
		return stream;
	}

	@Override
	public byte[] getBytes() {
		if ( bytes == null ) {
			try {
				bytes = stream.readAllBytes();
			}
			catch (IOException e) {
				throw new HibernateException( "IOException occurred reading a binary value", e );
			}
		}
		return bytes;
	}

	@Override
	public long getLength() {
		return length;
	}

	@Override
	public Blob asBlob(LobCreator lobCreator) {
		return lobCreator.createBlob( stream, length );
	}

	@Override
	public void release() {
		try {

View on GitHub (pinned to fad1729dce)

Solutions

  1. Do not consume the InputStream before/after giving it to Hibernate; treat it as owned by Hibernate
  2. Read the bytes into a byte[] first and create the Blob from the array if the source cannot stay open until flush
  3. Keep the stream and its resource (file/connection) open until the transaction commits

Example fix

// before: stream may be closed by the time Hibernate reads it
entity.setAttachment(lobHelper.createBlob(socketStream, len));

// after: materialize up front
byte[] bytes = socketStream.readAllBytes();
entity.setAttachment(lobHelper.createBlob(bytes));
Defensive patterns

Strategy: validation

Validate before calling

// ensure the stream is fully readable before handing it over
if (!stream.markSupported()) { /* wrap or materialize */ }
byte[] bytes = stream.readAllBytes(); // materialize once, up front
entity.setAttachment(lobHelper.createBlob(bytes));

Try / catch

try {
    session.flush();
}
catch (HibernateException e) {
    if (e.getCause() instanceof java.io.IOException io) {
        // the backing stream failed: re-open source and rebind a materialized value
    }
}

Prevention

When it happens

Trigger: A Blob/binary value created from an InputStream (e.g. Hibernate.getLobHelper().createBlob(stream, length)) whose underlying stream is already consumed, closed, or fails when Hibernate finally reads it at flush/bind time.

Common situations: Reading the provided InputStream yourself before handing it to Hibernate; streams over files/sockets/LOB locators that are closed between entity update and flush; deferred flushes after the stream source went away.

Related errors


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