hibernate/hibernate-orm · error · UnsupportedOperationException

Clobs are not cacheable

Error message

Clobs are not cacheable

What it means

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.

Source

Thrown at hibernate-core/src/main/java/org/hibernate/type/descriptor/java/ClobJavaType.java:181

		return dialect.getDefaultLobLength();
	}

	/**
	 * MutabilityPlan for Clob values
	 */
	public static class ClobMutabilityPlan implements MutabilityPlan<Clob> {
		public static final ClobMutabilityPlan INSTANCE = new ClobMutabilityPlan();

		public boolean isMutable() {
			return false;
		}

		public Clob deepCopy(Clob value) {
			return value;
		}

		public Serializable disassemble(Clob value, SharedSessionContract session) {
			throw new UnsupportedOperationException( "Clobs are not cacheable" );
		}

		public Clob assemble(Serializable cached, SharedSessionContract session) {
			throw new UnsupportedOperationException( "Clobs are not cacheable" );
		}
	}
}

View on GitHub (pinned to fad1729dce)

Solutions

  1. Map the attribute as String with @Lob (materialized and cacheable) instead of java.sql.Clob.
  2. Mark the entity @Cacheable(false) if it must keep the Clob attribute.
  3. Move the CLOB to a separate, non-cached entity (one-to-one) and cache the rest.

Example fix

// before
@Entity @Cacheable
public class Document {
    @Lob private java.sql.Clob content; // cache put -> UnsupportedOperationException
}

// after
@Entity @Cacheable
public class Document {
    @Lob private String content; // materialized, serializable, cacheable
}
Defensive patterns

Strategy: validation

Validate before calling

// run once at startup: refuse to enable caching on Clob-bearing entities
for (EntityType<?> t : metamodel.getEntities()) {
    boolean cached = t.getJavaType().isAnnotationPresent(jakarta.persistence.Cacheable.class);
    for (Attribute<?,?> a : t.getAttributes()) {
        if (cached && a.getJavaType() == java.sql.Clob.class) {
            throw new IllegalStateException(t.getName() + '.' + a.getName() + " is Clob and not cacheable");
        }
    }
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


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