quarkusio/quarkus · error · IllegalStateException

Method 'TenantResolver.resolveTenantId()' returned a null va

Error message

Method 'TenantResolver.resolveTenantId()' returned a null value. Unfortunately Hibernate ORM does not allow null for tenant identifiers. Please use a non-null value!

What it means

Hibernate ORM forbids null tenant identifiers. Quarkus' HibernateCurrentTenantIdentifierResolver calls the application's TenantResolver.resolveTenantId() and throws IllegalStateException when it returns null, telling you to return a non-null value.

Source

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

    private final String persistenceUnitName;

    public HibernateCurrentTenantIdentifierResolver(String persistenceUnitName) {
        this.persistenceUnitName = persistenceUnitName;
    }

    @Override
    public String resolveCurrentTenantIdentifier() {

        // Make sure that we're in a request
        if (!Arc.container().requestContext().isActive()) {
            return null;
        }

        TenantResolver resolver = tenantResolver(persistenceUnitName);
        String tenantId = resolver.resolveTenantId();
        if (tenantId == null) {
            throw new IllegalStateException("Method 'TenantResolver.resolveTenantId()' returned a null value. "
                    + "Unfortunately Hibernate ORM does not allow null for tenant identifiers. "
                    + "Please use a non-null value!");
        }
        LOG.debugv("resolveCurrentTenantIdentifier(): {0}", tenantId);
        return tenantId;

    }

    @Override
    public boolean validateExistingCurrentSessions() {
        return false;
    }

    @Override
    public boolean isRoot(String tenantId) {
        // Make sure that we're in a request
        if (!Arc.container().requestContext().isActive()) {
            return false;

View on GitHub (pinned to e1c734241f)

Solutions

  1. Return a non-null default tenant id from resolveTenantId() when no tenant context is available
  2. Reject the request earlier (e.g. in a filter/interceptor) when the tenant identifier is missing, before Hibernate resolves it
  3. Make the resolver fail fast with your own descriptive exception (e.g. 400 Bad Request) instead of returning null
  4. Test with an explicit tenant header/path so the resolver never receives null input

Example fix

// before
public String resolveTenantId() {
    return headers.getHeaderString("X-Tenant"); // may be null -> throws
}
// after
public String resolveTenantId() {
    String t = headers.getHeaderString("X-Tenant");
    return t != null ? t : "default";
}
Defensive patterns

Strategy: validation

Validate before calling

String tenantId = resolver.resolveTenantId();
if (tenantId == null) {
    tenantId = "default"; // or reject request before Hibernate resolves tenants
}

Type guard

Optional<String> safeTenant(TenantResolver r) {
    return Optional.ofNullable(r.resolveTenantId());
}

Try / catch

try {
    doJpaWork();
} catch (IllegalStateException e) {
    if (e.getMessage().contains("returned a null value")) {
        Log.error("TenantResolver returned null; provide a default or reject the request");
        throw new BadRequestException("Missing tenant context");
    }
    throw e;
}

Prevention

When it happens

Trigger: A registered TenantResolver whose resolveTenantId() returns null at runtime — e.g. no tenant context in the request (missing header/path segment), unauthenticated request where the resolver derives the tenant from the security identity, or a test/mock resolver returning null.

Common situations: Resolver extracting tenant from an HTTP header that isn't present; SecurityIdentity-dependent resolver hit on the login/unauthenticated endpoint; forgetting a default/fallback tenant id for non-tenant endpoints.

Related errors


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