{"record":{"id":"1f72d1543a606fc0","repo":"hibernate/hibernate-orm","slug":"column-mappings-for-property-propertyname-mix-1f72d1","errorCode":null,"errorMessage":"Column mappings for property '${propertyName}' mix insertable with 'insertable=false'","messagePattern":"Column mappings for property '(.+?)' mix insertable with 'insertable=false'","errorType":"exception","errorClass":"AnnotationException","httpStatus":null,"severity":"error","filePath":"hibernate-core/src/main/java/org/hibernate/boot/model/internal/AnnotatedColumns.java","lineNumber":169,"sourceCode":"\t}\n\n\tpublic void addColumn(AnnotatedColumn child) {\n\t\tcolumns.add( child );\n\t}\n\n\tpublic void checkPropertyConsistency() {\n\t\tif ( columns.size() > 1 ) {\n\t\t\tfor ( int currentIndex = 1; currentIndex < columns.size(); currentIndex++ ) {\n\t\t\t\tfinal AnnotatedColumn current = columns.get( currentIndex );\n\t\t\t\tfinal AnnotatedColumn previous = columns.get( currentIndex - 1 );\n\t\t\t\tif ( !current.isFormula() && !previous.isFormula() ) {\n\t\t\t\t\tif ( current.isNullable() != previous.isNullable() ) {\n\t\t\t\t\t\tthrow new AnnotationException(\n\t\t\t\t\t\t\t\t\"Column mappings for property '\" + propertyName + \"' mix nullable with 'not null'\"\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t\tif ( current.isInsertable() != previous.isInsertable() ) {\n\t\t\t\t\t\tthrow new AnnotationException(\n\t\t\t\t\t\t\t\t\"Column mappings for property '\" + propertyName + \"' mix insertable with 'insertable=false'\"\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t\tif ( current.isUpdatable() != previous.isUpdatable() ) {\n\t\t\t\t\t\tthrow new AnnotationException(\n\t\t\t\t\t\t\t\t\"Column mappings for property '\" + propertyName + \"' mix updatable with 'updatable=false'\"\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t\tif ( !current.getExplicitTableName().equals( previous.getExplicitTableName() ) ) {\n\t\t\t\t\t\tthrow new AnnotationException(\n\t\t\t\t\t\t\t\t\"Column mappings for property '\" + propertyName + \"' mix distinct secondary tables\"\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}","sourceCodeStart":151,"sourceCodeEnd":187,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/boot/model/internal/AnnotatedColumns.java#L151-L187","documentation":"The insertability leg of AnnotatedColumns.checkPropertyConsistency: consecutive non-formula columns of one property must agree on insertable. If one column writes on insert and a sibling of the same property has insertable = false, the mapping is contradictory and Hibernate throws this AnnotationException while binding the property.","triggerScenarios":"A multi-column property where @Column/@AttributeOverride entries mix insertable = true (default) and insertable = false - commonly the read-only half of a composite mapping left non-insertable while the other half stays writable.","commonSituations":"Making one column of a composite read-only for trigger/generated-value reasons while forgetting the sibling columns; copy-pasted override blocks with stale insertable flags; splitting a property's columns across insert/update strategies.","solutions":["Set the same insertable value on every column of the property","If one part must stay read-only, map it as its own property (e.g. a separate read-only field) rather than mixing flags inside one mapping","After fixing, verify updatable flags and table names too - the same consistency check validates them next"],"exampleFix":"// before: mixed insertable within one property\n@Type(MoneyType.class)\n@Columns({\n    @Column(name = \"amount\"),                          // insertable = true\n    @Column(name = \"currency\", insertable = false)     // mixes -> error\n})\nprivate Money price;\n\n// after: consistent flags (or split into separate properties)\n@Type(MoneyType.class)\n@Columns({\n    @Column(name = \"amount\"),\n    @Column(name = \"currency\")\n})\nprivate Money price;","handlingStrategy":"validation","validationCode":"// Before boot: all columns of one multi-column property must agree on insertable\nstatic boolean insertableFlagsConsistent(Class<?> entity) {\n    for (Field f : entity.getDeclaredFields()) {\n        Columns cols = f.getAnnotation(Columns.class);\n        if (cols == null || cols.value().length < 2) continue;\n        boolean first = cols.value()[0].insertable();\n        for (Column c : cols.value()) {\n            if (c.insertable() != first) return false;\n        }\n    }\n    return true;\n}","typeGuard":null,"tryCatchPattern":"try {\n    final SessionFactory sf = new MetadataSources(standardServiceRegistry)\n            .addAnnotatedClass(MyEntity.class)\n            .buildMetadata()\n            .buildSessionFactory();\n} catch (AnnotationException | MappingException e) {\n    throw new IllegalStateException(\"Invalid ORM mapping, aborting startup: \" + e.getMessage(), e);\n}","preventionTips":["Never mix writable and read-only columns inside one property mapping","Model read-only companions as separate properties","When changing one column's flags, sweep the whole @Columns/@AttributeOverrides block"],"tags":["hibernate","jpa","multi-column","insertable","consistency","mapping"],"backgroundTag":"inconsistent-column-mapping-flags","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}