hibernate/hibernate-orm · error · UnsupportedOperationException

Blobs are not cacheable

Error message

Blobs are not cacheable

What it means

BlobJavaType's mutability plan deliberately refuses to disassemble java.sql.Blob values: a Blob is a live handle on the JDBC connection/locator and cannot be serialized into the second-level cache. When an entity holding a Blob attribute is put into the shared cache, disassemble throws this UnsupportedOperationException ('Blobs are not cacheable').

Source

Thrown at hibernate-core/src/main/java/org/hibernate/type/descriptor/java/BlobJavaType.java:55

public class BlobJavaType extends AbstractClassJavaType<Blob> {
	public static final BlobJavaType INSTANCE = new BlobJavaType();

	public static class BlobMutabilityPlan implements MutabilityPlan<Blob> {
		public static final BlobMutabilityPlan INSTANCE = new BlobMutabilityPlan();

		@Override
		public boolean isMutable() {
			return false;
		}

		@Override
		public Blob deepCopy(Blob value) {
			return value;
		}

		@Override
		public Serializable disassemble(Blob value, SharedSessionContract session) {
			throw new UnsupportedOperationException( "Blobs are not cacheable" );
		}

		@Override
		public Blob assemble(Serializable cached, SharedSessionContract session) {
			throw new UnsupportedOperationException( "Blobs are not cacheable" );
		}
	}

	public BlobJavaType() {
		super( Blob.class, BlobMutabilityPlan.INSTANCE, IncomparableComparator.INSTANCE );
	}

	@Override
	public boolean isInstance(Object value) {
		return value instanceof Blob;
	}

	@Override

View on GitHub (pinned to fad1729dce)

Solutions

  1. Map the attribute as byte[] instead of java.sql.Blob (fully materialized, cacheable)
  2. Keep Blob but exclude the entity from the second-level cache (remove @Cacheable/@Cache)
  3. Split the LOB into a separate non-cached entity and cache only the metadata part
  4. Alternatively use a converter that materializes byte[] for the cached form

Example fix

// before
@Entity
@Cacheable
@org.hibernate.annotations.Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
public class Attachment {
    @Id private Long id;
    private Blob content; // disassemble -> 'Blobs are not cacheable'
}
// after
@Entity
@Cacheable
@org.hibernate.annotations.Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
public class Attachment {
    @Id private Long id;
    private byte[] content; // materialized, cache-safe
}
Defensive patterns

Strategy: fallback

Validate before calling

// startup audit: no cached entity may hold java.sql.Blob/Clob attributes
for (Class<?> entity : annotatedEntities) {
    if (entity.isAnnotationPresent(Cacheable.class)
            || entity.isAnnotationPresent(org.hibernate.annotations.Cache.class)) {
        for (Field f : entity.getDeclaredFields()) {
            if (Blob.class.isAssignableFrom(f.getType()) || Clob.class.isAssignableFrom(f.getType())) {
                throw new MappingException("Cached entity " + entity + " has LOB field " + f);
            }
        }
    }
}

Type guard

static boolean isCacheSafeLobMapping(Class<?> fieldType) {
    return !java.sql.Blob.class.isAssignableFrom(fieldType)
        && !java.sql.Clob.class.isAssignableFrom(fieldType); // byte[]/String are fine
}

Try / catch

// no meaningful retry: catch to convert into a clear configuration error
try {
    session.persist(attachment);
} catch (UnsupportedOperationException e) {
    if (String.valueOf(e.getMessage()).contains("Blobs are not cacheable")) {
        throw new MappingException("Remove " + Attachment.class.getSimpleName()
            + " from the 2nd-level cache or map its LOB as byte[]", e);
    }
    throw e;
}

Prevention

When it happens

Trigger: An entity with a java.sql.Blob attribute is annotated @Cacheable / included in a @Cache region; the first flush/load that writes the entity into the second-level cache invokes disassemble and fails.

Common situations: Turning on second-level cache (or adding the entity to a region) for legacy entities that map LOBs as java.sql.Blob; enabling query caching which caches entity identifiers/data; moving from byte[] to Blob mapping for streaming while keeping the cache annotation.

Related errors


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