{"record":{"id":"ab8d4407d5e0c6e0","repo":"hibernate/hibernate-orm","slug":"unable-to-access-blob-stream","errorCode":null,"errorMessage":"Unable to access blob stream","messagePattern":"Unable to access blob stream","errorType":"exception","errorClass":"HibernateException","httpStatus":null,"severity":"error","filePath":"hibernate-core/src/main/java/org/hibernate/type/descriptor/java/BlobJavaType.java","lineNumber":90,"sourceCode":"\n\t@Override\n\tpublic Blob cast(Object value) {\n\t\treturn (Blob) value;\n\t}\n\n\t@Override\n\tpublic String extractLoggableRepresentation(Blob value) {\n\t\treturn value == null ? \"null\" : \"{blob}\";\n\t}\n\n\t@Override\n\tpublic String toString(Blob value) {\n\t\tfinal byte[] bytes;\n\t\ttry {\n\t\t\tbytes = extractBytes( value.getBinaryStream() );\n\t\t}\n\t\tcatch ( SQLException e ) {\n\t\t\tthrow new HibernateException( \"Unable to access blob stream\", e );\n\t\t}\n\t\treturn PrimitiveByteArrayJavaType.INSTANCE.toString( bytes );\n\t}\n\n\t@Override\n\tpublic Blob fromString(CharSequence string) {\n\t\treturn BlobProxy.generateProxy( PrimitiveByteArrayJavaType.INSTANCE.fromString( string ) );\n\t}\n\n\t@Override\n\tpublic int extractHashCode(Blob value) {\n\t\treturn System.identityHashCode( value );\n\t}\n\n\t@Override\n\tpublic boolean areEqual(Blob one, Blob another) {\n\t\treturn one == another;\n\t}","sourceCodeStart":72,"sourceCodeEnd":108,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/BlobJavaType.java#L72-L108","documentation":"Thrown by BlobJavaType.toString(Blob) when Hibernate materializes a java.sql.Blob into its string form. The method opens value.getBinaryStream() and fully reads it via DataHelper.extractBytes; any SQLException from the driver (invalid or freed locator, closed connection, driver limit) is wrapped in HibernateException with this message. Blob locators are only valid while the connection/transaction that produced them is still alive.","triggerScenarios":"Calling toString()/logging on a detached entity that holds a Blob attribute; dirty-check or TRACE logging that stringifies the Blob; converting a Blob-typed query result to String after the transaction committed; Oracle freeing a temporary LOB on commit, or the stream already having been consumed once.","commonSituations":"Entities with java.sql.Blob @Lob fields included in toString()/log statements; access after the session closed (OSIV disabled); batch jobs carrying entities across transactions; driver-specific LOB lifetime quirks (Oracle temp LOBs, PostgreSQL Large Objects).","solutions":["Exclude Blob attributes from toString()/logging; never stringify live LOB handles.","Map the attribute as byte[] with @Lob instead of java.sql.Blob so the data is materialized eagerly at read time.","Access and convert the Blob inside the same open session/transaction that loaded it.","If the stream was consumed, re-query the entity in a fresh session before converting."],"exampleFix":"// before\n@Lob @Basic(fetch = FetchType.LAZY)\nprivate java.sql.Blob data;\nlog.info(\"loaded {}\", entity); // toString() touches the Blob -> HibernateException\n\n// after\n@Lob\nprivate byte[] data; // materialized during row read\nlog.info(\"loaded {} bytes\", entity.getData().length);","handlingStrategy":"try-catch","validationCode":"// only convert while the session that loaded the Blob is alive\nif (!session.isOpen() || !session.isConnected()) {\n    throw new IllegalStateException(\"Reload the entity in an open session before touching the Blob\");\n}","typeGuard":null,"tryCatchPattern":"try {\n    return PrimitiveByteArrayJavaType.INSTANCE.toString(extractBytes(blob.getBinaryStream()));\n} catch (HibernateException e) {\n    if (e.getCause() instanceof SQLException) {\n        // locator died: re-load in a fresh transaction or surface a domain error\n        throw new IllegalStateException(\"Blob for entity \" + id + \" is no longer readable\", e);\n    }\n    throw e;\n}","preventionTips":["Never include java.sql.Blob fields in toString()/equals()/log output.","Prefer byte[] + @Lob mappings unless streaming is required.","Materialize LOB content inside the loading transaction; never after commit.","Keep LOB-touching code off lazy-init paths that can run post-session."],"tags":["hibernate","blob","lob","jdbc","stream"],"backgroundTag":"blob-stream-access","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}