hibernate/hibernate-orm · error · IllegalArgumentException
Unknown TcclLookupPrecedence - {}
Error message
Unknown TcclLookupPrecedence - {} What it means
TcclLookupPrecedence controls when the thread-context ClassLoader is consulted by Hibernate's aggregated ClassLoader. The value is read from the setting hibernate.classLoader.tccl_lookup_precedence (AvailableSettings.TC_CLASSLOADER), and this implementation accepts only the explicit strings NEVER and BEFORE (case-insensitive); anything else - including a literal 'after' - throws IllegalArgumentException. When the property is absent, the default (AFTER, applied by BootstrapServiceRegistryBuilder/PersistenceXmlParser) is used silently.
Source
Thrown at hibernate-core/src/main/java/org/hibernate/boot/registry/classloading/internal/TcclLookupPrecedence.java:69
* @return The precedence, or {@code defaultValue} if none was specified.
* @throws IllegalArgumentException If there is a setting defined for
* precedence, but it is not a legal value
*/
public static TcclLookupPrecedence from(Map<?,?> settings, TcclLookupPrecedence defaultValue) {
final String explicitSetting = (String) settings.get( AvailableSettings.TC_CLASSLOADER );
if ( explicitSetting == null ) {
return defaultValue;
}
if ( NEVER.name().equalsIgnoreCase( explicitSetting ) ) {
return NEVER;
}
if ( BEFORE.name().equalsIgnoreCase( explicitSetting ) ) {
return BEFORE;
}
throw new IllegalArgumentException( "Unknown TcclLookupPrecedence - " + explicitSetting );
}
}
View on GitHub (pinned to fad1729dce)
Solutions
- Set the property to never or before (case-insensitive), or remove it entirely to accept the default precedence
- Check the property source for trailing whitespace, quotes, or casing artifacts
- Upgrade Hibernate if you need a version that accepts the explicit 'after' literal
Example fix
// before <property name="hibernate.classLoader.tccl_lookup_precedence" value="after"/> <!-- rejected --> // after <!-- omit the property for the default (AFTER), or use: --> <property name="hibernate.classLoader.tccl_lookup_precedence" value="before"/>
Defensive patterns
Strategy: validation
Validate before calling
// Validate the enum-like property before boot
Object v = settings.get("hibernate.classLoader.tccl_lookup_precedence");
if (v != null) {
String s = v.toString().trim();
if (!("never".equalsIgnoreCase(s) || "before".equalsIgnoreCase(s))) {
throw new IllegalStateException(
"hibernate.classLoader.tccl_lookup_precedence must be never or before, got: " + s);
}
} Try / catch
try {
TcclLookupPrecedence.from(settings);
} catch (IllegalArgumentException e) {
// strip the property and retry with the default to unblock boot, then fix the value
settings.remove("hibernate.classLoader.tccl_lookup_precedence");
throw e;
} Prevention
- Treat the TCCL precedence property as an enum: only never/before accepted explicitly
- Add config validation (Spring Boot metadata / OWASP-style checks) that whitelists known enum values
- Beware literal 'after' - omit the property to get the default precedence
When it happens
Trigger: Setting hibernate.classLoader.tccl_lookup_precedence in persistence.xml, hibernate.cfg.xml, or the settings map to any value other than never/before - e.g. 'after', 'true', 'always', or a typo - during TcclLookupPrecedence.from(settings) at bootstrap.
Common situations: Typo'd or legacy values copied from other frameworks; assuming 'AFTER' is an accepted literal in this version; XML/YAML quoting or trailing whitespace corrupting the value; classloader troubleshooting cargo-culted from old blog posts.
Related errors
- Unable to load class [" + className + "]
- Unable to resolve name [{}] as strategy [{}]
- Default resolver threw exception
- Unable to access JDBC metadata
- Multiple MutationExecutorService service registrations found
AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22).
Data as JSON: /api/errors/5d754d2c295c80fd.
Report an issue: GitHub.