{"record":{"id":"c136daf937f48510","repo":"hibernate/hibernate-orm","slug":"all-tenantid-fields-must-have-the-same-type-par","errorCode":null,"errorMessage":"all @TenantId fields must have the same type: <parameterTypeName> differs from <tenantIdTypeName>","messagePattern":"all @TenantId fields must have the same type: <parameterTypeName> differs from <tenantIdTypeName>","errorType":"exception","errorClass":"MappingException","httpStatus":null,"severity":"error","filePath":"hibernate-core/src/main/java/org/hibernate/binder/internal/TenantIdBinder.java","lineNumber":68,"sourceCode":"\t\t\tcollector.addFilterDefinition(\n\t\t\t\t\tnew FilterDefinition(\n\t\t\t\t\t\t\tFILTER_NAME,\n\t\t\t\t\t\t\t\"\",\n\t\t\t\t\t\t\tfalse,\n\t\t\t\t\t\t\ttrue,\n\t\t\t\t\t\t\tsingletonMap( PARAMETER_NAME, tenantIdType ),\n\t\t\t\t\t\t\temptyMap()\n\t\t\t\t\t)\n\t\t\t);\n\t\t}\n\t\telse {\n\t\t\tfinal var tenantIdTypeJtd = tenantIdType.getJavaTypeDescriptor();\n\t\t\tfinal var jdbcMapping = filterDefinition.getParameterJdbcMapping( PARAMETER_NAME );\n\t\t\tassert jdbcMapping != null;\n\t\t\tfinal var parameterJavaType = jdbcMapping.getJavaTypeDescriptor();\n\t\t\tif ( !parameterJavaType.getJavaTypeClass()\n\t\t\t\t\t.equals( tenantIdTypeJtd.getJavaTypeClass() ) ) {\n\t\t\t\tthrow new MappingException(\n\t\t\t\t\t\t\"all @TenantId fields must have the same type: \"\n\t\t\t\t\t\t\t\t+ parameterJavaType.getTypeName()\n\t\t\t\t\t\t\t\t+ \" differs from \"\n\t\t\t\t\t\t\t\t+ tenantIdTypeJtd.getTypeName()\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t\tpersistentClass.addFilter(\n\t\t\t\tFILTER_NAME,\n\t\t\t\tcolumnNameOrFormula( property )\n\t\t\t\t\t\t+ \" = :\"\n\t\t\t\t\t\t+ PARAMETER_NAME,\n\t\t\t\ttrue,\n\t\t\t\temptyMap(),\n\t\t\t\temptyMap()\n\t\t);\n\n\t\tif ( isRowLevelSecurityEnabled( buildingContext ) ) {","sourceCodeStart":50,"sourceCodeEnd":86,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/binder/internal/TenantIdBinder.java#L50-L86","documentation":"Hibernate implements @TenantId as one shared filter definition whose parameter type is fixed by the first @TenantId attribute bound. For every subsequent entity, TenantIdBinder compares the filter parameter's Java type with that entity's @TenantId property type; any difference (String vs Long, String vs UUID, etc.) throws a MappingException naming both types at metadata build time.","triggerScenarios":"Two or more entities declare @TenantId with different Java types — e.g. @TenantId String tenantId on Customer and @TenantId Long tenantId on Order — and SessionFactory bootstrap binds the tenant filter for the later entity and detects the mismatch.","commonSituations":"Incrementally adding @TenantId to new entities using a different id type than existing ones; mixed legacy schemas (BIGINT tenant keys in some tables, VARCHAR in others); a half-finished migration from numeric tenant codes to UUIDs.","solutions":["Pick one tenant id Java type (String, UUID, Long, ...) and use it for every @TenantId attribute in the whole domain.","Where DB column types differ, unify them with a schema migration rather than mixing Java types.","If types truly must differ per table, @TenantId cannot be used — switch to explicit @FilterDef/@Filter with per-entity conditions."],"exampleFix":"// before\n@Entity public class Customer { @TenantId String tenantId; ... }\n@Entity public class Order    { @TenantId Long tenantId; ... }\n\n// after\n@Entity public class Customer { @TenantId String tenantId; ... }\n@Entity public class Order    { @TenantId String tenantId; ... }","handlingStrategy":"validation","validationCode":"Set<Class<?>> tenantIdTypes = new HashSet<>();\nfor (Class<?> cls : entityClasses) {\n    for (Field f : cls.getDeclaredFields()) {\n        if (f.isAnnotationPresent(org.hibernate.annotations.TenantId.class)) {\n            tenantIdTypes.add(f.getType());\n        }\n    }\n}\nif (tenantIdTypes.size() > 1) {\n    throw new IllegalStateException(\"Conflicting @TenantId types: \" + tenantIdTypes);\n}","typeGuard":null,"tryCatchPattern":"Catch org.hibernate.MappingException during SessionFactory build; the message names both conflicting types. Fix the mapping — no runtime recovery exists.","preventionTips":["Standardize one tenant id Java type across the whole domain before adopting @TenantId.","Add a build-time check that all @TenantId fields share the same type.","Complete tenant-id type migrations in one release, not incrementally per entity."],"tags":["hibernate","multi-tenancy","tenant-id","orm-mapping","annotations"],"backgroundTag":"tenant-id-type-mismatch","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}