{"record":{"id":"83411b30da1b74a2","repo":"hibernate/hibernate-orm","slug":"cannot-redefine-the-read-only-mode-on-a-child-sess","errorCode":null,"errorMessage":"Cannot redefine the read-only mode on a child session if the connection is reused","messagePattern":"Cannot redefine the read-only mode 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/SharedSessionBuilderImpl.java","lineNumber":72,"sourceCode":"\t@Override\n\t@Nonnull\n\tpublic SharedSessionBuilderImplementor withOption(EntityManager.CreationOption option) {\n\t\toptions.apply( option );\n\t\treturn this;\n\t}\n\n\t@Override\n\t@Nonnull\n\tpublic SessionImplementor open() {\n\t\tCORE_LOGGER.openingSession( options.getTenantIdentifierValue() );\n\t\tif ( original.getFactory().getSessionFactoryOptions().isMultiTenancyEnabled() ) {\n\t\t\tif ( options.isTransactionCoordinatorShared() ) {\n\t\t\t\tif ( tenantIdChanged ) {\n\t\t\t\t\tthrow new SessionException(\n\t\t\t\t\t\t\t\"Cannot redefine the tenant identifier on a child session if the connection is reused\" );\n\t\t\t\t}\n\t\t\t\tif ( readOnlyChanged ) {\n\t\t\t\t\tthrow new SessionException(\n\t\t\t\t\t\t\t\"Cannot redefine the read-only mode on a child session if the connection is reused\" );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn createSession( options );\n\t}\n\n\t@Override\n\t@Nonnull\n\tpublic SessionImplementor openSession() {\n\t\treturn open();\n\t}\n\n\t@Override\n\t@Nonnull\n\tpublic SharedSessionBuilderImplementor tenantIdentifier(Object tenantIdentifier) {\n\t\tsuper.tenantIdentifier( tenantIdentifier );\n\t\ttenantIdChanged = true;","sourceCodeStart":54,"sourceCodeEnd":90,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/engine/creation/internal/SharedSessionBuilderImpl.java#L54-L90","documentation":"Same guard as the tenant check in SharedSessionBuilderImpl.open(): when a child session shares the parent's transaction coordinator (and physical connection) under multi-tenancy, Hibernate also refuses to change the read-only mode. Calling readOnly(...) on the shared-session builder sets readOnlyChanged, and open() throws because the shared connection/transaction is already in the parent's read-only mode.","triggerScenarios":"session.sessionWithOptions()...openSession() with transaction/connection sharing and multi-tenancy enabled, where .readOnly(true) or .readOnly(false) is called with a value different from the original session's read-only setting.","commonSituations":"Read-only report sessions derived from a read-write request session; utility code that 'optimizes' child sessions with .readOnly(true); refactoring code so that a shared builder now toggles read-only.","solutions":["Remove the .readOnly(...) call from the shared-session builder and keep the parent's mode.","Set the read-only mode you need on the parent session before deriving the child.","Open an independent session (factory.openSession()) instead of sharing when read/write semantics must differ.","Use session.setDefaultReadOnly()/setReadOnly(entity, ...) on the original session rather than redefining it on a shared child."],"exampleFix":"// before - child shares connection but flips read-only -> SessionException\nSession child = parent.sessionWithOptions()\n        .connection()\n        .readOnly(true)        // different from parent's mode\n        .openSession();\n// after - apply the mode on the parent, then share\nparent.setDefaultReadOnly(true);\nSession child = parent.sessionWithOptions().connection().openSession();","handlingStrategy":"validation","validationCode":"// Only derive a shared child session when the read-only mode will not change\nboolean sameReadOnly = parentSession.isDefaultReadOnly();\nSessionBuilder<?> b = parentSession.sessionWithOptions().connection();\n// do NOT call b.readOnly(...) with a different value; keep parent's mode\nreturn b.openSession();","typeGuard":null,"tryCatchPattern":"catch (SessionException e) {\n    if (e.getMessage() != null && e.getMessage().contains(\"read-only mode on a child session\")) {\n        return factory.openSession(); // independent session, its own mode allowed\n    }\n    throw e;\n}","preventionTips":["Set read-only on the parent session before spawning shared children.","Never toggle readOnly() on a builder that shares the transaction coordinator.","Use session.setDefaultReadOnly() on the original session for read-only optimization."],"tags":["multi-tenancy","session","read-only","shared-connection","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"}