hibernate/hibernate-orm · error · SQLException

could not reset reader

Error message

could not reset reader

What it means

In BlobProxy.resetIfNeeded(), InputStream.reset() itself threw an IOException (stream closed, or read past the mark limit — the mark is set with limit = length+1 bytes) and is rethrown as SQLException('could not reset reader'). Unlike 'Underlying stream does not allow reset', here the stream claims reset support but the reset failed at runtime.

Source

Thrown at hibernate-core/src/main/java/org/hibernate/engine/jdbc/proxy/BlobProxy.java:107

		resetIfNeeded();
		return binaryStream;
	}

	private void resetIfNeeded() throws SQLException {
		try {
			if ( needsReset ) {
				final InputStream inputStream = binaryStream.getInputStream();
				if ( !resetAllowed && inputStream != null) {
					throw new SQLException( "Underlying stream does not allow reset" );
				}
				if ( inputStream != null ) {
					inputStream.reset();
					setStreamMark();
				}
			}
		}
		catch ( IOException ioe) {
			throw new SQLException("could not reset reader");
		}
		needsReset = true;
	}

	/**
	 * Generates a BlobImpl using byte data.
	 *
	 * @param bytes The data to be created as a Blob.
	 *
	 * @return The BlobProxy instance to represent this data.
	 */
	public static Blob generateProxy(byte[] bytes) {
		return new BlobProxy( bytes );
	}

	/**
	 * Generates a BlobImpl proxy using a given number of bytes from an InputStream.
	 *

View on GitHub (pinned to fad1729dce)

Solutions

  1. Pass the exact byte length when creating the Blob (or avoid the length-based API and use byte[])
  2. Materialize the content in memory (byte[]) if the Blob may be read more than once
  3. Ensure nothing closes or fully drains the underlying stream before Hibernate finishes with it

Example fix

// before: wrong length invalidates the mark
Blob b = lobHelper.createBlob(in, guessedLength /* too small */);

// after: exact length or full materialization
Blob b = lobHelper.createBlob(in, in.available()); // when exact
// better: byte[] bytes = in.readAllBytes(); Blob b = lobHelper.createBlob(bytes);
Defensive patterns

Strategy: validation

Validate before calling

// pass the exact length so the internal mark limit is correct
long len = countExactBytes(source); // do not guess
Blob b = lobHelper.createBlob(new BufferedInputStream(source), len);

Prevention

When it happens

Trigger: A stream-backed Blob whose underlying stream is read beyond its declared length (mark of length+1 bytes invalidated), closed between accesses, or otherwise invalidated — then accessed a second time, triggering the rewind.

Common situations: Passing an inaccurate length to createBlob(stream, length) so the mark buffer is too small; another component closing the underlying stream before flush; large streams wrapped with small fixed buffers.

Related errors


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