{"record":{"id":"a25c7977e36a4abc","repo":"hibernate/hibernate-orm","slug":"cannot-redefine-the-tenant-identifier-on-a-child-s-a25c79","errorCode":null,"errorMessage":"Cannot redefine the tenant identifier on a child session if the connection is reused","messagePattern":"Cannot redefine the tenant identifier on a child session if the connection is reused","errorType":"exception","errorClass":"SessionException","httpStatus":null,"severity":"error","filePath":"hibernate-core/src/main/java/org/hibernate/engine/creation/internal/SharedStatelessSessionBuilderImpl.java","lineNumber":61,"sourceCode":"\n\t@Override\n\tprotected SharedStatelessSessionBuilder getThis() {\n\t\treturn this;\n\t}\n\n\t// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\t// SharedStatelessSessionBuilder\n\n\t@Override\n\t@Nonnull\n\tpublic StatelessSessionImplementor open() {\n\t\tCORE_LOGGER.openingStatelessSession( options.getTenantIdentifierValue() );\n\t\tif ( original.getSessionFactory().getSessionFactoryOptions().isMultiTenancyEnabled() ) {\n\t\t\tif ( options.isTransactionCoordinatorShared() ) {\n\t\t\t\tfinal var tenantId = original.getTenantIdentifierValue();\n\t\t\t\tassert tenantId != null;\n\t\t\t\tif ( !Objects.equals( tenantId, options.getTenantIdentifierValue() ) ) {\n\t\t\t\t\tthrow new SessionException( \"Cannot redefine the tenant identifier on a child session if the connection is reused\" );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn createStatelessSession( options );\n\t}\n\n\t@Override\n\t@Nonnull\n\tpublic StatelessSession openStatelessSession() {\n\t\treturn open();\n\t}\n\n\t@Override\n\t@Nonnull\n\tpublic SharedStatelessSessionBuilder connection() {\n\t\toptions.shareTransactionContext();\n\t\treturn this;\n\t}","sourceCodeStart":43,"sourceCodeEnd":79,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/engine/creation/internal/SharedStatelessSessionBuilderImpl.java#L43-L79","documentation":"Stateless-session variant of the tenant guard in SharedStatelessSessionBuilderImpl.open(): when the derived stateless session shares the original's transaction coordinator under multi-tenancy, Hibernate compares the builder's tenant identifier with the original session's and throws if they differ. A shared connection is already associated with the original tenant, so a different tenant identifier would violate isolation.","triggerScenarios":"statelessSession.sessionWithOptions()...openStatelessSession() (or .open()) with transaction/connection sharing and multi-tenancy enabled, where .tenantIdentifier(...) was called with a value not equal to the original session's tenant (the builder throws on any non-equal value, since the original tenant is asserted non-null).","commonSituations":"Batch import/export jobs deriving stateless sessions from a tenant session but targeting another tenant; refactor where the tenant id parameter stopped matching the session's tenant; multi-tenant bulk processing pipelines.","solutions":["Drop the .tenantIdentifier(...) call if the child should keep the original tenant.","Open an independent stateless session from the factory with the target tenant: factory.openStatelessSession(tenantId).","Do not share the transaction coordinator if the child must run under another tenant.","Assert in code that derived stateless sessions always pass the same tenant id as the parent."],"exampleFix":"// before - shared connection, different tenant -> SessionException\nStatelessSession child = parentStateless.sessionWithOptions()\n        .transaction()\n        .tenantIdentifier(\"tenant-b\")\n        .openStatelessSession();\n// after - separate stateless session per tenant\nStatelessSession child = sessionFactory.openStatelessSession(tenantBIdentifier);","handlingStrategy":"validation","validationCode":"// For shared stateless child sessions, pass the parent's tenant identifier only\nObject parentTenant = parentStateless.getTenantIdentifierValue();\nStatelessSessionBuilder b = parentStateless.sessionWithOptions().transaction();\nif (targetTenant != null && !Objects.equals(targetTenant, parentTenant)) {\n    return factory.openStatelessSession(targetTenant); // separate connection\n}\nreturn b.openStatelessSession();","typeGuard":null,"tryCatchPattern":"catch (SessionException e) {\n    if (e.getMessage() != null && e.getMessage().contains(\"tenant identifier on a child session\")) {\n        return factory.openStatelessSession(targetTenantId);\n    }\n    throw e;\n}","preventionTips":["Derive shared stateless sessions only within the same tenant scope.","Add an assertion in batch-job bootstrap: child tenant id equals parent tenant id.","Open stateless sessions per tenant from the factory in multi-tenant batch pipelines."],"tags":["multi-tenancy","stateless-session","shared-connection","tenant-isolation","session-builder"],"backgroundTag":"multi-tenant-session-misuse","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}