{"record":{"id":"9eeb08d515bfe396","repo":"hibernate/hibernate-orm","slug":"clobs-are-not-cacheable","errorCode":null,"errorMessage":"Clobs are not cacheable","messagePattern":"Clobs are not cacheable","errorType":"exception","errorClass":"UnsupportedOperationException","httpStatus":null,"severity":"error","filePath":"hibernate-core/src/main/java/org/hibernate/type/descriptor/java/ClobJavaType.java","lineNumber":181,"sourceCode":"\t\treturn dialect.getDefaultLobLength();\n\t}\n\n\t/**\n\t * MutabilityPlan for Clob values\n\t */\n\tpublic static class ClobMutabilityPlan implements MutabilityPlan<Clob> {\n\t\tpublic static final ClobMutabilityPlan INSTANCE = new ClobMutabilityPlan();\n\n\t\tpublic boolean isMutable() {\n\t\t\treturn false;\n\t\t}\n\n\t\tpublic Clob deepCopy(Clob value) {\n\t\t\treturn value;\n\t\t}\n\n\t\tpublic Serializable disassemble(Clob value, SharedSessionContract session) {\n\t\t\tthrow new UnsupportedOperationException( \"Clobs are not cacheable\" );\n\t\t}\n\n\t\tpublic Clob assemble(Serializable cached, SharedSessionContract session) {\n\t\t\tthrow new UnsupportedOperationException( \"Clobs are not cacheable\" );\n\t\t}\n\t}\n}\n","sourceCodeStart":163,"sourceCodeEnd":189,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/ClobJavaType.java#L163-L189","documentation":"ClobJavaType.ClobMutabilityPlan.disassemble throws UnsupportedOperationException('Clobs are not cacheable') when the second-level cache serializes an entity (or collection element) that holds a java.sql.Clob attribute. A Clob is a live handle to driver/connection state, so Hibernate refuses to put it into the cache region.","triggerScenarios":"Annotating an entity with java.sql.Clob attributes as @Cacheable (or enabling hibernate.cache.default_cache_concurrency_strategy globally); the cache put happens on the first insert/load of such an entity and fails.","commonSituations":"Rolling out caching onto legacy entities during performance work; a global default cache strategy setting catching entities with LOB fields; framework upgrades that enable caching by default.","solutions":["Map the attribute as String with @Lob (materialized and cacheable) instead of java.sql.Clob.","Mark the entity @Cacheable(false) if it must keep the Clob attribute.","Move the CLOB to a separate, non-cached entity (one-to-one) and cache the rest."],"exampleFix":"// before\n@Entity @Cacheable\npublic class Document {\n    @Lob private java.sql.Clob content; // cache put -> UnsupportedOperationException\n}\n\n// after\n@Entity @Cacheable\npublic class Document {\n    @Lob private String content; // materialized, serializable, cacheable\n}","handlingStrategy":"validation","validationCode":"// run once at startup: refuse to enable caching on Clob-bearing entities\nfor (EntityType<?> t : metamodel.getEntities()) {\n    boolean cached = t.getJavaType().isAnnotationPresent(jakarta.persistence.Cacheable.class);\n    for (Attribute<?,?> a : t.getAttributes()) {\n        if (cached && a.getJavaType() == java.sql.Clob.class) {\n            throw new IllegalStateException(t.getName() + '.' + a.getName() + \" is Clob and not cacheable\");\n        }\n    }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Never map java.sql.Clob on entities you plan to cache; use @Lob String.","Watch hibernate.cache.default_cache_concurrency_strategy — it can cache entities you never audited.","Cover caching rollout with an integration test that inserts every cached entity once."],"tags":["hibernate","clob","second-level-cache","mapping"],"backgroundTag":"lob-not-cacheable","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}