{"record":{"id":"e4a3211186207e7d","repo":"hibernate/hibernate-orm","slug":"tenantid-attribute-must-be-mapped-to-a-single-col","errorCode":null,"errorMessage":"@TenantId attribute must be mapped to a single column or formula","messagePattern":"@TenantId attribute must be mapped to a single column or formula","errorType":"exception","errorClass":"MappingException","httpStatus":null,"severity":"error","filePath":"hibernate-core/src/main/java/org/hibernate/binder/internal/TenantIdBinder.java","lineNumber":139,"sourceCode":"\t\t\t\t\t\thasTenantCredentialsMapper( buildingContext )\n\t\t\t\t\t\t\t&& rowLevelSecurity.supportsTenantIdentifierSource( TenantIdentifierSource.DATABASE_USER )\n\t\t\t\t\t\t\t\t? TenantIdentifierSource.DATABASE_USER\n\t\t\t\t\t\t\t\t: TenantIdentifierSource.SESSION\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate static boolean hasTenantCredentialsMapper(MetadataBuildingContext buildingContext) {\n\t\tfinal var bootstrapContext = buildingContext.getBootstrapContext();\n\t\tfinal var settings = bootstrapContext.getConfigurationService().getSettings();\n\t\treturn settings.get( MULTI_TENANT_CREDENTIALS_MAPPER ) != null\n\t\t\t|| getTenantCredentialsMapper( settings, bootstrapContext.getServiceRegistry() ) != null;\n\t}\n\n\tprivate String columnNameOrFormula(Property property) {\n\t\tif ( property.getColumnSpan() != 1 ) {\n\t\t\tthrow new MappingException( \"@TenantId attribute must be mapped to a single column or formula\" );\n\t\t}\n\t\tfinal var selectable = property.getSelectables().get( 0 );\n\t\tif ( selectable instanceof Formula formula ) {\n\t\t\treturn formula.getFormula();\n\t\t}\n\t\telse if ( selectable instanceof Column column ) {\n\t\t\treturn column.getName();\n\t\t}\n\t\telse {\n\t\t\tthrow new AssertionFailure( \"@TenantId attribute must be mapped to a column or formula\" );\n\t\t}\n\t}\n\n}\n","sourceCodeStart":121,"sourceCodeEnd":154,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/binder/internal/TenantIdBinder.java#L121-L154","documentation":"TenantIdBinder builds the tenant filter condition from exactly one selectable of the @TenantId property (a single column or a single formula). If the property maps to zero or multiple columns — a composite/embedded tenant id — property.getColumnSpan() != 1 and binding throws a MappingException.","triggerScenarios":"@TenantId placed on a property mapped to more than one column: an @EmbeddedId component, a composite user type, or an attribute spanning several columns via @Columns.","commonSituations":"Composite tenancy keys (tenant_id + region) required by legacy schemas; putting @TenantId on a field of an @EmbeddedId class; migrating from hand-written @Filter SQL (which allowed arbitrary expressions) to @TenantId.","solutions":["Map the tenant discriminator as a single basic column or a single formula.","Combine multi-part tenancy into one column/formula, or go back to explicit @FilterDef/@Filter for composite tenant matching.","Never annotate fields inside @EmbeddedId or embeddable classes with @TenantId."],"exampleFix":"// before\n@Embeddable public class TenantKey { String group; String region; }\n@Entity public class Doc {\n    @EmbeddedId @TenantId TenantKey id;\n}\n\n// after\n@Entity public class Doc {\n    @Id long id;\n    @TenantId String tenantId; // single column\n}","handlingStrategy":"validation","validationCode":"for (Class<?> cls : embeddableClasses) {\n    for (Field f : cls.getDeclaredFields()) {\n        if (f.isAnnotationPresent(org.hibernate.annotations.TenantId.class)) {\n            throw new IllegalStateException(\"@TenantId inside embeddable/composite key \" + cls.getName());\n        }\n    }\n}","typeGuard":null,"tryCatchPattern":"Catch org.hibernate.MappingException during bootstrap; the message identifies the @TenantId mapping. Fix the mapping to a single column or formula.","preventionTips":["Model the tenant discriminator as one basic column.","Never place @TenantId inside @EmbeddedId or composite types.","Use @FilterDef/@Filter when composite tenant matching is unavoidable."],"tags":["hibernate","multi-tenancy","tenant-id","composite-key","orm-mapping"],"backgroundTag":"tenant-id-mapping-error","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}