hibernate/hibernate-orm · error · IllegalArgumentException

JDBC type-code [%s (%s)] not known to have a corresponding L

Error message

JDBC type-code [%s (%s)] not known to have a corresponding LOB equivalent, and Java type is not Serializable (to use BLOB)

What it means

Thrown while SimpleValue resolves the JDBC type code for a @Lob/@Nationalized-lob mapped attribute. When the value is marked as a LOB, Hibernate maps the recommended DDL type code to its LOB variant (e.g. VARCHAR to LONGVARCHAR/CLOB). If the recommended code (like TIMESTAMP for java.time.Instant, or DATE) has no LOB equivalent, the only escape hatch is BLOB serialization — allowed only when the Java type implements Serializable. When neither condition holds, this IllegalArgumentException is thrown.

Source

Thrown at hibernate-core/src/main/java/org/hibernate/mapping/SimpleValue.java:774

				metadata.getTypeConfiguration().getJdbcTypeRegistry()
						.getDescriptor( jdbcTypeCode( recommendedJdbcType, domainJavaType ) ),
				jpaAttributeConverter
		);
	}

	private <T> int jdbcTypeCode(JdbcType recommendedJdbcType, JavaType<T> domainJavaType) {
		final int recommendedDdlTypeCode = recommendedJdbcType.getDdlTypeCode();
		final int jdbcTypeCode;
		if ( isLob() ) {
			if ( isMappedToKnownLobCode( recommendedDdlTypeCode ) ) {
				jdbcTypeCode = getLobCodeTypeMapping( recommendedDdlTypeCode );
			}
			else {
				if ( Serializable.class.isAssignableFrom( domainJavaType.getJavaTypeClass() ) ) {
					jdbcTypeCode = Types.BLOB;
				}
				else {
					throw new IllegalArgumentException(
							String.format(
									Locale.ROOT,
									"JDBC type-code [%s (%s)] not known to have a corresponding LOB equivalent, and Java type is not Serializable (to use BLOB)",
									recommendedDdlTypeCode,
									JdbcTypeNameMapper.getTypeName( recommendedDdlTypeCode )
							)
					);
				}
			}
		}
		else {
			jdbcTypeCode = recommendedDdlTypeCode;
		}
		return isNationalized() ? toNationalizedTypeCode( jdbcTypeCode ) : jdbcTypeCode;
	}

	public boolean isTypeSpecified() {
		return typeName != null;

View on GitHub (pinned to fad1729dce)

Solutions

  1. Remove @Lob from the non-LOB-mappable attribute and control length/precision with @Column(length=...), @JdbcTypeCode, or the dialect default.
  2. If serialized storage is acceptable, make the attribute's Java type implement java.io.Serializable so the BLOB fallback applies.
  3. For Strings needing unlimited length use @JdbcTypeCode(SqlTypes.LONGVARCHAR) or @Column(columnDefinition="clob") instead of forcing LOB on a temporal/UUID type.
  4. Verify with MetadataBuilder + SchemaExport in a test so the mapping fails at build time with a clear location.

Example fix

// before
@Lob
private Instant createdOn;  // Instant is not Serializable and TIMESTAMP has no LOB form

// after
@Column(name = "created_on")
private Instant createdOn;
Defensive patterns

Strategy: type-guard

Validate before calling

// before applying @Lob, check the Java type is either LOB-mappable or Serializable
static boolean lobSafe(Class<?> javaType) {
    return Serializable.class.isAssignableFrom(javaType)
        || CharSequence.class.isAssignableFrom(javaType)
        || javaType == byte[].class || javaType == char[].class;
}
// usage: assert lobSafe(field.getType()) before registering mappings

Type guard

static boolean supportsLobMapping(Class<?> javaType) {
    return Serializable.class.isAssignableFrom(javaType)
            || CharSequence.class.isAssignableFrom(javaType)
            || javaType.isArray(); // byte[]/char[] have LONGVARBINARY/LONGVARCHAR equivalents
}

Try / catch

try {
    sf = new Configuration().addAnnotatedClass(Entity.class).buildSessionFactory();
} catch (IllegalArgumentException | MappingException e) {
    if (e.getMessage() != null && e.getMessage().contains("not known to have a corresponding LOB equivalent")) {
        throw new IllegalStateException("@Lob is unsupported for this property type; remove @Lob or make the type Serializable", e);
    }
    throw e;
}

Prevention

When it happens

Trigger: Annotating a field of a non-Serializable, non-LOB-mappable type with @Lob — typical examples: @Lob on java.time.Instant, java.time.LocalDate, java.util.UUID mapped to a non-SqlType, or an enum mapped to INTEGER — then triggering type resolution (SessionFactory bootstrap or schema export).

Common situations: Developers add @Lob hoping for unlimited length on temporal or UUID columns; upgrading Hibernate where previously the type silently resolved; mapping custom value types that don't implement Serializable with @Lob; combining @Lob with @JdbcTypeCode(Types.TIMESTAMP).

Related errors


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