hibernate/hibernate-orm · error · IllegalStateException

Clobs may not be accessed after serialization

Error message

Clobs may not be accessed after serialization

What it means

SerializableClobProxy mirrors the Blob variant: it makes a Clob serializable through a JDK dynamic proxy, but the wrapped Clob field is transient, so a Java serialization round trip nulls it. Afterward getWrappedClob() - and every Clob method routed through invoke() - throws IllegalStateException("Clobs may not be accessed after serialization"). The character data was never written to the serial form.

Source

Thrown at hibernate-core/src/main/java/org/hibernate/engine/jdbc/proxy/SerializableClobProxy.java:47

	/**
	 * Builds a serializable {@link Clob} wrapper around the given {@link Clob}.
	 *
	 * @param clob The {@link Clob} to be wrapped.
	 * @see #generateProxy(Clob)
	 */
	protected SerializableClobProxy(Clob clob) {
		this.clob = clob;
	}

	/**
	 * Access to the wrapped Clob reference
	 *
	 * @return The wrapped Clob reference
	 */
	public Clob getWrappedClob() {
		if ( clob == null ) {
			throw new IllegalStateException( "Clobs may not be accessed after serialization" );
		}
		else {
			return clob;
		}
	}

	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		if ( "getWrappedClob".equals( method.getName() ) ) {
			return getWrappedClob();
		}
		try {
			return method.invoke( getWrappedClob(), args );
		}
		catch ( AbstractMethodError e ) {
			throw new HibernateException( "The JDBC driver does not implement the method: " + method, e );
		}
		catch ( InvocationTargetException e ) {

View on GitHub (pinned to fad1729dce)

Solutions

  1. Map the attribute as String instead of Clob so the text itself is serialized
  2. Reload the entity by id in the new session instead of reusing the serialized instance
  3. If serialization is unavoidable, extract first (clob.getSubString(1, (int) clob.length())) and rebuild with Hibernate.getLobHelper().createClob(text)
  4. Keep LOB-bearing entities within a single session/transaction boundary

Example fix

// before
@Entity class Article { @Lob Clob body; }
 session.setAttribute("article", article); // after replication: IllegalStateException

// after
@Entity class Article {
    @Lob String body;  // plain serializable text; set via clob.getSubString(1, (int) clob.length())
}
Defensive patterns

Strategy: validation

Validate before calling

// Run BEFORE serializing anything that might hold a Hibernate Clob proxy
static String detachClob(java.sql.Clob clob) throws SQLException {
    try {
        return clob.getSubString(1, (int) clob.length()); // works on the live proxy
    } catch (IllegalStateException e) {
        throw new IllegalStateException(
            "Clob already deserialized/empty - reload the entity in this session", e);
    }
}
// store detachClob(clob) instead of the proxy

Try / catch

try {
    text = clob.getSubString(1, (int) clob.length());
} catch (IllegalStateException e) {
    if (e.getMessage() != null && e.getMessage().contains("after serialization")) {
        entity = session.find(Entity.class, id);      // only recovery: re-fetch the row
        text = entity.getBody();
    } else {
        throw e;
    }
}

Prevention

When it happens

Trigger: Putting a Hibernate-proxied Clob into a replicated HttpSession (Spring Session, cluster failover); a detached entity with a Clob attribute stored in a store-by-value cache or shipped over RMI/Java serialization; calling ((WrappedClob) proxy).getWrappedClob() after deserialization.

Common situations: Clustered web apps keeping text-heavy entities in session; serializing detached entities to message queues; JSF view state or conversational state holding entities with Clob fields.

Related errors


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