hibernate/hibernate-orm · error · SQLException

Underlying stream does not allow reset

Error message

Underlying stream does not allow reset

What it means

BlobProxy wraps a stream-backed Blob created via generateProxy(InputStream, length). After the stream has been read once (needsReset), later access goes through resetIfNeeded(), which rewinds the stream with InputStream.reset(). resetAllowed is only true when the stream supported mark/reset at construction (markSupported()); otherwise it throws SQLException('Underlying stream does not allow reset').

Source

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

		}
	}

	private InputStream getStream() throws SQLException {
		return getUnderlyingStream().getInputStream();
	}

	@Override
	public BinaryStream getUnderlyingStream() throws SQLException {
		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.
	 *

View on GitHub (pinned to fad1729dce)

Solutions

  1. Wrap the stream in a mark/reset-capable stream first, e.g. new BufferedInputStream(in) (buffered when reasonably small) — or read all bytes and use createBlob(byte[])
  2. Ensure the Blob content is read only once, or buffer it fully in memory for large-object handling
  3. Prefer byte[]- or String-backed LOBs when the source stream cannot be re-read

Example fix

// before: stream that cannot reset
Blob b = session.getLobHelper().createBlob(socketStream, len);

// after: mark/reset capable or fully materialized
Blob b = session.getLobHelper().createBlob(new BufferedInputStream(socketStream), len);
// or: Blob b = session.getLobHelper().createBlob(socketStream.readAllBytes());
Defensive patterns

Strategy: validation

Validate before calling

// only hand reset-capable streams to createBlob
InputStream in = rawStream.markSupported() ? rawStream : new BufferedInputStream(rawStream);
Blob b = session.getLobHelper().createBlob(in, length);

Type guard

static boolean blobResetSafe(InputStream in) {
    return in == null || in.markSupported();
}

Prevention

When it happens

Trigger: Creating a Blob from an InputStream that does not support mark/reset (raw socket stream, some compression/DB LOB streams) via Hibernate.getLobHelper().createBlob(stream, length), then reading the Blob more than once — e.g. the driver reads it to send data and Hibernate/driver reads it again for length or logging.

Common situations: Streaming uploads straight from sockets or crypto/compression streams into Blob fields; drivers that consume the Blob twice (statement logging, p6spy, replication); re-reading a materialized proxy after a failed statement.

Related errors


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