hibernate/hibernate-orm · critical · HibernateException

illegal value for configuration setting…

Error message

illegal value for configuration setting 'hibernate.connection.datasource'

What it means

DataSourceBasedMultiTenantConnectionProviderImpl.injectServices reads the setting hibernate.connection.datasource and requires it to be a String holding a JNDI name, because this provider locates per-tenant DataSources through JNDI. If the value is absent or not a String (e.g. a DataSource instance was placed in the settings map), Hibernate throws HibernateException with this message during ServiceRegistry injection at bootstrap.

Solutions

  1. Set the property to the JNDI name string, e.g. hibernate.connection.datasource=java:/datasources/tenants
  2. If you do not use JNDI, replace this provider with a custom MultiTenantConnectionProvider that maps tenant identifiers to DataSource instances directly
  3. Verify no code overrides the property with a non-String value after configuration merging

Example fix

// before
Map<String,Object> settings = new HashMap<>();
settings.put(AvailableSettings.DATASOURCE, myDataSourceObject); // not a String -> HibernateException

// after
settings.put(AvailableSettings.DATASOURCE, "java:/datasources/tenants");
Defensive patterns

Strategy: validation

Validate before calling

// validate before building the SessionFactory
Object v = settings.get(AvailableSettings.DATASOURCE);
if ( providerIsDataSourceBased && !(v instanceof String jndiName) ) {
    throw new IllegalArgumentException(
        "hibernate.connection.datasource must be a JNDI name String, got: " + v);
}

Try / catch

try {
    sf = builder.build();
} catch (HibernateException e) {
    if ( e.getMessage() != null && e.getMessage().contains("hibernate.connection.datasource") ) {
        throw new ConfigurationException("Fix hibernate.connection.datasource to a JNDI name String", e);
    }
    throw e;
}

Prevention

When it happens

Trigger: Configuring hibernate.multiTenancy with DataSourceBasedMultiTenantConnectionProviderImpl while AvailableSettings.DATASOURCE ('hibernate.connection.datasource') is missing, or is a javax.sql.DataSource object, Integer, or any non-String value in the properties map passed to sessionFactory building.

Common situations: Spring Boot or programmatic bootstrap putting a DataSource bean into hibernate properties instead of a JNDI name; copy-pasted persistence.xml where <jta-data-source>/<non-jta-data-source> semantics differ; migrating a working single-tenant JNDI setup where the property was omitted.

Understand the failure class

Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.

Related errors


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

Appendix: source

Thrown at hibernate-core/src/main/java/org/hibernate/engine/jdbc/connections/spi/DataSourceBasedMultiTenantConnectionProviderImpl.java:77

	protected DataSource selectDataSource(T tenantIdentifier) {
		DataSource dataSource = dataSourceMap().get( tenantIdentifier );
		if ( dataSource == null ) {
			dataSource = (DataSource) jndiService.locate( baseJndiNamespace + '/' + tenantIdentifier );
			dataSourceMap().put( tenantIdentifier, dataSource );
		}
		return dataSource;
	}

	private Map<T, DataSource> dataSourceMap() {
		return dataSourceMap;
	}

	@Override
	public void injectServices(@Nonnull ServiceRegistryImplementor serviceRegistry) {
		final var configurationService = serviceRegistry.requireService( ConfigurationService.class );
		final Object dataSourceConfigValue = configurationService.getSettings().get( DATASOURCE );
		if ( !(dataSourceConfigValue instanceof String configuredJndiName) ) {
			throw new HibernateException( "illegal value for configuration setting '" + DATASOURCE + "'" );
		}
		jndiName = configuredJndiName;

		jndiService = serviceRegistry.getService( JndiService.class );
		if ( jndiService == null ) {
			throw new HibernateException( "Could not locate JndiService from DataSourceBasedMultiTenantConnectionProviderImpl" );
		}

		final Object namedObject = jndiService.locate( this.jndiName );
		if ( namedObject == null ) {
			throw new HibernateException( "JNDI name [" + this.jndiName + "] could not be resolved" );
		}
		else if ( namedObject instanceof DataSource datasource ) {
			final int loc = jndiName.lastIndexOf( '/' );
			baseJndiNamespace = jndiName.substring( 0, loc );
			final String prefix = jndiName.substring( loc + 1);
			tenantIdentifierForAny = (T) prefix;
			dataSourceMap().put( tenantIdentifierForAny, datasource );

View on GitHub (pinned to fad1729dce)