{"record":{"id":"af6ed9f1b7036fc7","repo":"quarkusio/quarkus","slug":"method-tenantconnectionresolver-resolve-string","errorCode":null,"errorMessage":"Method 'TenantConnectionResolver.resolve(String)' returned a null value. This violates the contract of the interface!","messagePattern":"Method 'TenantConnectionResolver\\.resolve\\(String\\)' returned a null value\\. This violates the contract of the interface!","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"extensions/hibernate-orm/runtime/src/main/java/io/quarkus/hibernate/orm/runtime/tenant/HibernateMultiTenantConnectionProvider.java","lineNumber":97,"sourceCode":"    private static ConnectionProvider resolveConnectionProvider(String persistenceUnitName, String tenantIdentifier) {\n        LOG.debugv(\"resolveConnectionProvider(persistenceUnitName={0}, tenantIdentifier={1})\", persistenceUnitName,\n                tenantIdentifier);\n        // TODO when we switch to the non-legacy method, don't forget to update the definition of the default bean\n        //   of type DataSourceTenantConnectionResolver (add the @PersistenceUnitExtension qualifier to that bean)\n        InjectableInstance<TenantConnectionResolver> instance = PersistenceUnitUtil\n                .legacySingleExtensionInstanceForPersistenceUnit(\n                        TenantConnectionResolver.class, persistenceUnitName);\n        if (instance.isUnsatisfied()) {\n            throw new IllegalStateException(\n                    String.format(\n                            Locale.ROOT, \"No instance of %1$s was found for persistence unit %2$s. \"\n                                    + \"You need to create an implementation for this interface to allow resolving the current tenant connection.\",\n                            TenantConnectionResolver.class.getSimpleName(), persistenceUnitName));\n        }\n        TenantConnectionResolver resolver = instance.get();\n        ConnectionProvider cp = resolver.resolve(tenantIdentifier);\n        if (cp == null) {\n            throw new IllegalStateException(\"Method 'TenantConnectionResolver.\"\n                    + \"resolve(String)' returned a null value. This violates the contract of the interface!\");\n        }\n        return cp;\n    }\n\n    /**\n     * Retrieves the tenant resolver or fails if it is not available.\n     *\n     * @return Current tenant resolver.\n     */\n    private static InstanceHandle<TenantResolver> tenantResolver(String persistenceUnitName) {\n        InjectableInstance<TenantResolver> instance = PersistenceUnitUtil\n                .legacySingleExtensionInstanceForPersistenceUnit(\n                        TenantResolver.class, persistenceUnitName);\n\n        if (instance.isUnsatisfied()) {\n            throw new IllegalStateException(String.format(Locale.ROOT,\n                    \"No instance of %1$s was found for persistence unit %2$s. \"","sourceCodeStart":79,"sourceCodeEnd":115,"githubUrl":"https://github.com/quarkusio/quarkus/blob/e1c734241f34c7919086ceb4c9262b4a58f6de44/extensions/hibernate-orm/runtime/src/main/java/io/quarkus/hibernate/orm/runtime/tenant/HibernateMultiTenantConnectionProvider.java#L79-L115","documentation":"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.","triggerScenarios":"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.","commonSituations":"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).","solutions":["Make resolve() return a valid ConnectionProvider for the tenant or throw a descriptive exception when the tenant is unknown","Add configuration for the missing tenant datasource/schema","Validate the incoming tenant id against an allowlist before passing it to Hibernate","Log the offending tenantIdentifier to spot mismatches"],"exampleFix":"// before\n@Override\npublic ConnectionProvider resolve(String tenantId) {\n    return providers.get(tenantId); // null for unknown tenant\n}\n\n// after\n@Override\npublic ConnectionProvider resolve(String tenantId) {\n    ConnectionProvider cp = providers.get(tenantId);\n    if (cp == null) {\n        throw new IllegalArgumentException(\"Unknown tenant: \" + tenantId);\n    }\n    return cp;\n}","handlingStrategy":"validation","validationCode":"Set<String> knownTenants = loadTenantConfig();\nif (!knownTenants.contains(incomingTenantId)) {\n    throw new IllegalArgumentException(\"Unknown tenant: \" + incomingTenantId);\n}","typeGuard":"Predicate<String> isKnownTenant = t -> t != null && tenantProviders.containsKey(t);","tryCatchPattern":"try {\n    em.find(E.class, id);\n} catch (IllegalStateException e) {\n    if (e.getMessage().contains(\"resolve(String)\")) { throw new UnknownTenantException(currentTenantId); }\n    throw e;\n}","preventionTips":["Validate incoming tenant ids against configured tenants/datasources before DB access","Never return null from resolve(); throw or fall back to a documented default","Keep tenant ids case-consistent between headers and configuration keys"],"tags":["hibernate-orm","multi-tenancy","null-return","contract-violation"],"backgroundTag":"tenant-resolver-returned-null","analyzedSha":"e1c734241f34c7919086ceb4c9262b4a58f6de44","analyzedAt":"2026-09-05T17:01:29.979Z","contentChangedAt":"2026-09-05T17:01:29.979Z","schemaVersion":2},"datasetVersion":"2026-09-12T22:17:10.623Z"}