quarkusio/quarkus · error · IllegalStateException

Method 'TenantConnectionResolver.resolve(String)' returned a

Error message

Method 'TenantConnectionResolver.resolve(String)' returned a null value. This violates the contract of the interface!

What it means

The contract of TenantConnectionResolver.resolve(String) requires a non-null ConnectionProvider. Quarkus throws IllegalStateException when a registered resolver returns null for the given tenant identifier.

Source

Thrown at extensions/hibernate-orm/runtime/src/main/java/io/quarkus/hibernate/orm/runtime/tenant/HibernateMultiTenantConnectionProvider.java:97

    private static ConnectionProvider resolveConnectionProvider(String persistenceUnitName, String tenantIdentifier) {
        LOG.debugv("resolveConnectionProvider(persistenceUnitName={0}, tenantIdentifier={1})", persistenceUnitName,
                tenantIdentifier);
        // TODO when we switch to the non-legacy method, don't forget to update the definition of the default bean
        //   of type DataSourceTenantConnectionResolver (add the @PersistenceUnitExtension qualifier to that bean)
        InjectableInstance<TenantConnectionResolver> instance = PersistenceUnitUtil
                .legacySingleExtensionInstanceForPersistenceUnit(
                        TenantConnectionResolver.class, persistenceUnitName);
        if (instance.isUnsatisfied()) {
            throw new IllegalStateException(
                    String.format(
                            Locale.ROOT, "No instance of %1$s was found for persistence unit %2$s. "
                                    + "You need to create an implementation for this interface to allow resolving the current tenant connection.",
                            TenantConnectionResolver.class.getSimpleName(), persistenceUnitName));
        }
        TenantConnectionResolver resolver = instance.get();
        ConnectionProvider cp = resolver.resolve(tenantIdentifier);
        if (cp == null) {
            throw new IllegalStateException("Method 'TenantConnectionResolver."
                    + "resolve(String)' returned a null value. This violates the contract of the interface!");
        }
        return cp;
    }

    /**
     * Retrieves the tenant resolver or fails if it is not available.
     *
     * @return Current tenant resolver.
     */
    private static InstanceHandle<TenantResolver> tenantResolver(String persistenceUnitName) {
        InjectableInstance<TenantResolver> instance = PersistenceUnitUtil
                .legacySingleExtensionInstanceForPersistenceUnit(
                        TenantResolver.class, persistenceUnitName);

        if (instance.isUnsatisfied()) {
            throw new IllegalStateException(String.format(Locale.ROOT,
                    "No instance of %1$s was found for persistence unit %2$s. "

View on GitHub (pinned to e1c734241f)

Solutions

  1. Make resolve() return a valid ConnectionProvider for the tenant or throw a descriptive exception when the tenant is unknown
  2. Add configuration for the missing tenant datasource/schema
  3. Validate the incoming tenant id against an allowlist before passing it to Hibernate
  4. Log the offending tenantIdentifier to spot mismatches

Example fix

// before
@Override
public ConnectionProvider resolve(String tenantId) {
    return providers.get(tenantId); // null for unknown tenant
}

// after
@Override
public ConnectionProvider resolve(String tenantId) {
    ConnectionProvider cp = providers.get(tenantId);
    if (cp == null) {
        throw new IllegalArgumentException("Unknown tenant: " + tenantId);
    }
    return cp;
}
Defensive patterns

Strategy: validation

Validate before calling

Set<String> knownTenants = loadTenantConfig();
if (!knownTenants.contains(incomingTenantId)) {
    throw new IllegalArgumentException("Unknown tenant: " + incomingTenantId);
}

Type guard

Predicate<String> isKnownTenant = t -> t != null && tenantProviders.containsKey(t);

Try / catch

try {
    em.find(E.class, id);
} catch (IllegalStateException e) {
    if (e.getMessage().contains("resolve(String)")) { throw new UnknownTenantException(currentTenantId); }
    throw e;
}

Prevention

When it happens

Trigger: Multi-tenancy enabled, a TenantConnectionResolver bean is found, but resolve(tenantIdentifier) returns null — e.g., the tenant id is unknown to the resolver and the implementation returns null instead of throwing.

Common situations: Request carries a tenant id with no matching datasource/tenant configuration; schema-based resolver gets a tenant with no mapped schema; typo in tenant id vs quarkus.datasource."<name>" config keys; version changes in how tenant identifiers are resolved (case sensitivity).

Related errors


AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05). Data as JSON: /api/errors/af6ed9f1b7036fc7. Report an issue: GitHub.