{"record":{"id":"dd4955630054e817","repo":"hibernate/hibernate-orm","slug":"could-not-reset-reader","errorCode":null,"errorMessage":"could not reset reader","messagePattern":"could not reset reader","errorType":"exception","errorClass":"SQLException","httpStatus":null,"severity":"error","filePath":"hibernate-core/src/main/java/org/hibernate/engine/jdbc/proxy/BlobProxy.java","lineNumber":107,"sourceCode":"\t\tresetIfNeeded();\n\t\treturn binaryStream;\n\t}\n\n\tprivate void resetIfNeeded() throws SQLException {\n\t\ttry {\n\t\t\tif ( needsReset ) {\n\t\t\t\tfinal InputStream inputStream = binaryStream.getInputStream();\n\t\t\t\tif ( !resetAllowed && inputStream != null) {\n\t\t\t\t\tthrow new SQLException( \"Underlying stream does not allow reset\" );\n\t\t\t\t}\n\t\t\t\tif ( inputStream != null ) {\n\t\t\t\t\tinputStream.reset();\n\t\t\t\t\tsetStreamMark();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tcatch ( IOException ioe) {\n\t\t\tthrow new SQLException(\"could not reset reader\");\n\t\t}\n\t\tneedsReset = true;\n\t}\n\n\t/**\n\t * Generates a BlobImpl using byte data.\n\t *\n\t * @param bytes The data to be created as a Blob.\n\t *\n\t * @return The BlobProxy instance to represent this data.\n\t */\n\tpublic static Blob generateProxy(byte[] bytes) {\n\t\treturn new BlobProxy( bytes );\n\t}\n\n\t/**\n\t * Generates a BlobImpl proxy using a given number of bytes from an InputStream.\n\t *","sourceCodeStart":89,"sourceCodeEnd":125,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/engine/jdbc/proxy/BlobProxy.java#L89-L125","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Pass the exact byte length when creating the Blob (or avoid the length-based API and use byte[])","Materialize the content in memory (byte[]) if the Blob may be read more than once","Ensure nothing closes or fully drains the underlying stream before Hibernate finishes with it"],"exampleFix":"// before: wrong length invalidates the mark\nBlob b = lobHelper.createBlob(in, guessedLength /* too small */);\n\n// after: exact length or full materialization\nBlob b = lobHelper.createBlob(in, in.available()); // when exact\n// better: byte[] bytes = in.readAllBytes(); Blob b = lobHelper.createBlob(bytes);","handlingStrategy":"validation","validationCode":"// pass the exact length so the internal mark limit is correct\nlong len = countExactBytes(source); // do not guess\nBlob b = lobHelper.createBlob(new BufferedInputStream(source), len);","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Give accurate lengths to createBlob(stream, length)","Do not let other code close or drain the underlying stream","Materialize byte[] for values that may be read more than once"],"tags":["blob","stream","reset","io","hibernate"],"backgroundTag":"stream-mark-reset-unsupported","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}