{"record":{"id":"58add94c7ea5157e","repo":"quarkusio/quarkus","slug":"the-version-annotation-cannot-be-used-on-primit","errorCode":null,"errorMessage":"The '@Version' annotation cannot be used on primitive types. Offending entity is '${entity}'.","messagePattern":"The '@Version' annotation cannot be used on primitive types\\. Offending entity is '(.+?)'\\.","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"extensions/spring-data-jpa/deployment/src/main/java/io/quarkus/spring/data/deployment/generate/StockMethodsAdder.java","lineNumber":176,"sourceCode":"                        if (isPersistable(entityDotName)) {\n                            Expr isNew = bc.invokeVirtual(\n                                    ClassMethodDesc.of(ClassDesc.of(entityDotName.toString()), \"isNew\",\n                                            MethodTypeDesc.of(ConstantDescs.CD_boolean)),\n                                    entityParam);\n                            bc.ifElse(isNew,\n                                    tb -> generatePersistAndReturn(entityParam, tb, opsVar),\n                                    fb -> generateMergeAndReturn(entityParam, fb, opsVar,\n                                            entityClassVar));\n                        } else {\n                            AnnotationTarget idAnnotationTarget = getIdAnnotationTarget(entityDotName, index);\n                            Expr idValue = generateObtainValue(bc, entityDotName, entityParam, idAnnotationTarget);\n                            Type idType = getTypeOfTarget(idAnnotationTarget);\n                            Optional<AnnotationTarget> versionValueTarget = getVersionAnnotationTarget(entityDotName, index);\n\n                            if (versionValueTarget.isPresent()) {\n                                Type versionType = getTypeOfTarget(versionValueTarget.get());\n                                if (versionType instanceof PrimitiveType) {\n                                    throw new IllegalArgumentException(\n                                            \"The '@Version' annotation cannot be used on primitive types. Offending entity is '\"\n                                                    + entityDotName + \"'.\");\n                                }\n                                Expr versionValue = generateObtainValue(bc, entityDotName, entityParam,\n                                        versionValueTarget.get());\n                                bc.ifElse(bc.isNull(versionValue),\n                                        tb -> generatePersistAndReturn(entityParam, tb, opsVar),\n                                        fb -> generateMergeAndReturn(entityParam, fb, opsVar,\n                                                entityClassVar));\n                                // if version is present, we've handled both branches, so return here\n                                return;\n                            }\n\n                            if (idType instanceof PrimitiveType) {\n                                if (!idType.name().equals(DotNames.PRIMITIVE_LONG)\n                                        && !idType.name().equals(DotNames.PRIMITIVE_INTEGER)) {\n                                    throw new IllegalArgumentException(\n                                            \"Id type of '\" + entityDotName + \"' is invalid.\");","sourceCodeStart":158,"sourceCodeEnd":194,"githubUrl":"https://github.com/quarkusio/quarkus/blob/e1c734241f34c7919086ceb4c9262b4a58f6de44/extensions/spring-data-jpa/deployment/src/main/java/io/quarkus/spring/data/deployment/generate/StockMethodsAdder.java#L158-L194","documentation":"When generating the save() method, Quarkus distinguishes new vs existing entities by checking the @Version field. Spring Data JPA semantics require the version to be a nullable wrapper type (e.g. Long, Integer); a primitive version can never be null so newness cannot be detected. Quarkus rejects primitive @Version fields at augmentation time.","triggerScenarios":"An entity has a field annotated @Version with a primitive type (int, long, short, etc.); calling save() on that repository triggers generation of the version-comparison logic.","commonSituations":"Defining optimistic-locking version columns with int/long instead of Integer/Long; porting entities from codebases where the provider tolerated primitives.","solutions":["Change the @Version field type from primitive to its wrapper: int -> Integer, long -> Long","Use java.util.Optional-friendly nullable types and adjust getters/setters accordingly","If the schema column is NOT NULL, add a sensible default or let the persistence provider initialize the wrapper on insert"],"exampleFix":"// before\n@Version\nprivate long version;\n// after\n@Version\nprivate Long version;","handlingStrategy":"validation","validationCode":"// Verify @Version field is a wrapper type at entity design time\nField v = MyEntity.class.getDeclaredField(\"version\");\nif (v.getType().isPrimitive())\n    throw new IllegalStateException(\"@Version must not be primitive: \" + v.getType());","typeGuard":"boolean isValidVersionField(Field f) {\n    return f.isAnnotationPresent(jakarta.persistence.Version.class)\n        && !f.getType().isPrimitive();\n}","tryCatchPattern":null,"preventionTips":["Always declare @Version as Long/Integer (or java.util.Date/Instant/Timestamp)","Add an ArchUnit or annotation-processing check for primitive @Version fields","Review entity classes for optimistic-lock fields during code review"],"tags":["quarkus","spring-data-jpa","jpa","version","build-time"],"backgroundTag":"invalid-entity-field-type","analyzedSha":"e1c734241f34c7919086ceb4c9262b4a58f6de44","analyzedAt":"2026-09-05T17:01:29.979Z","contentChangedAt":"2026-09-05T17:01:29.979Z","schemaVersion":2},"datasetVersion":"2026-09-12T22:17:10.623Z"}