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

  1. Set the property to never or before (case-insensitive), or remove it entirely to accept the default precedence
  2. Check the property source for trailing whitespace, quotes, or casing artifacts
  3. 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

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


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