{"record":{"id":"d4b1c143521356a3","repo":"hibernate/hibernate-orm","slug":"could-not-locate-jndiservice-from-datasourcebasedm","errorCode":null,"errorMessage":"Could not locate JndiService from DataSourceBasedMultiTenantConnectionProviderImpl","messagePattern":"Could not locate JndiService from DataSourceBasedMultiTenantConnectionProviderImpl","errorType":"exception","errorClass":"HibernateException","httpStatus":null,"severity":"critical","filePath":"hibernate-core/src/main/java/org/hibernate/engine/jdbc/connections/spi/DataSourceBasedMultiTenantConnectionProviderImpl.java","lineNumber":83,"sourceCode":"\t\treturn dataSource;\n\t}\n\n\tprivate Map<T, DataSource> dataSourceMap() {\n\t\treturn dataSourceMap;\n\t}\n\n\t@Override\n\tpublic void injectServices(@Nonnull ServiceRegistryImplementor serviceRegistry) {\n\t\tfinal var configurationService = serviceRegistry.requireService( ConfigurationService.class );\n\t\tfinal Object dataSourceConfigValue = configurationService.getSettings().get( DATASOURCE );\n\t\tif ( !(dataSourceConfigValue instanceof String configuredJndiName) ) {\n\t\t\tthrow new HibernateException( \"illegal value for configuration setting '\" + DATASOURCE + \"'\" );\n\t\t}\n\t\tjndiName = configuredJndiName;\n\n\t\tjndiService = serviceRegistry.getService( JndiService.class );\n\t\tif ( jndiService == null ) {\n\t\t\tthrow new HibernateException( \"Could not locate JndiService from DataSourceBasedMultiTenantConnectionProviderImpl\" );\n\t\t}\n\n\t\tfinal Object namedObject = jndiService.locate( this.jndiName );\n\t\tif ( namedObject == null ) {\n\t\t\tthrow new HibernateException( \"JNDI name [\" + this.jndiName + \"] could not be resolved\" );\n\t\t}\n\t\telse if ( namedObject instanceof DataSource datasource ) {\n\t\t\tfinal int loc = jndiName.lastIndexOf( '/' );\n\t\t\tbaseJndiNamespace = jndiName.substring( 0, loc );\n\t\t\tfinal String prefix = jndiName.substring( loc + 1);\n\t\t\ttenantIdentifierForAny = (T) prefix;\n\t\t\tdataSourceMap().put( tenantIdentifierForAny, datasource );\n\t\t}\n\t\telse if ( namedObject instanceof Context ) {\n\t\t\tbaseJndiNamespace = jndiName;\n\t\t\tfinal Object configuredTenantId =\n\t\t\t\t\tconfigurationService.getSettings().get( TENANT_IDENTIFIER_TO_USE_FOR_ANY_KEY );\n\t\t\ttenantIdentifierForAny = (T) configuredTenantId;","sourceCodeStart":65,"sourceCodeEnd":101,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/engine/jdbc/connections/spi/DataSourceBasedMultiTenantConnectionProviderImpl.java#L65-L101","documentation":"During service injection, DataSourceBasedMultiTenantConnectionProviderImpl asks the ServiceRegistry for JndiService and gets null. JndiService is only available when JNDI integration is configured (typically via hibernate.jndi.* properties in a Java SE environment, or automatically inside an application server). Without it the provider cannot perform any JNDI lookups and fails fast at bootstrap.","triggerScenarios":"Bootstrap with DataSourceBasedMultiTenantConnectionProviderImpl in a plain Java SE environment or unit test where no JNDI provider is set up, so serviceRegistry.getService(JndiService.class) returns null.","commonSituations":"Running multitenancy unit tests outside a container; SE apps that forgot the hibernate.jndi.class / InitialContext factory settings; the JndiService initiator not registering a service because hibernate.jndi.class was not resolvable.","solutions":["Configure JNDI for SE use by setting the InitialContext factory (e.g. hibernate.jndi.class=org.osjava.sj.SimpleJndiContextFactory or your server's factory plus hibernate.jndi.url) so JndiService gets built","Prefer an embedded JNDI implementation (simple-jndi, naming-java) for tests","If JNDI is not an option, use a custom MultiTenantConnectionProvider that resolves DataSources from a map instead of JNDI"],"exampleFix":"// before (no JNDI config in SE)\nMap<String,Object> cfg = Map.of(\n    MultiTenancySettings.MULTI_TENANT_CONNECTION_PROVIDER, DataSourceBasedMultiTenantConnectionProviderImpl.class\n); // -> Could not locate JndiService\n\n// after\nMap<String,Object> cfg = Map.of(\n    MultiTenancySettings.MULTI_TENANT_CONNECTION_PROVIDER, DataSourceBasedMultiTenantConnectionProviderImpl.class,\n    AvailableSettings.DATASOURCE, \"java:/datasources/tenants\",\n    AvailableSettings.JNDI_CLASS, \"org.osjava.sj.SimpleJndiContextFactory\",\n    AvailableSettings.JNDI_URL, \"target/test-classes/simple-jndi\"\n);","handlingStrategy":"validation","validationCode":"// pre-flight: can we get an InitialContext at all in this environment?\ntry {\n    new InitialContext().getEnvironment();\n} catch (NamingException e) {\n    throw new IllegalStateException(\n        \"JNDI unavailable - configure hibernate.jndi.class or drop the JNDI-based multi-tenant provider\", e);\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["In Java SE or tests, always pair the JNDI-based provider with hibernate.jndi.class (+ hibernate.jndi.url) pointing at an embedded naming implementation","In CI, use simple-jndi or a custom JndiService instead of assuming container JNDI"],"tags":["hibernate","jndi","multitenancy","service-registry","bootstrap"],"backgroundTag":"jndi-not-configured","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}