{"record":{"id":"21755d78af3139b4","repo":"quarkusio/quarkus","slug":"type-classname-must-be-annotated-with-embeddab","errorCode":null,"errorMessage":"Type ${className} must be annotated with @Embeddable, because it is used as an embeddable. This type is used in class ${declaringClass} for attribute ${attribute}.","messagePattern":"Type (.+?) must be annotated with @Embeddable, because it is used as an embeddable\\. This type is used in class (.+?) for attribute (.+?)\\.","errorType":"validation","errorClass":"BuildException","httpStatus":null,"severity":"error","filePath":"extensions/hibernate-orm/deployment/src/main/java/io/quarkus/hibernate/orm/deployment/JpaJandexScavenger.java","lineNumber":584,"sourceCode":"    }\n\n    private void collectEmbeddedType(Set<DotName> embeddedTypes, ClassInfo declaringClass,\n            Declaration attribute, Type attributeType, boolean validate)\n            throws BuildException {\n        DotName className;\n        switch (attributeType.kind()) {\n            case CLASS:\n                className = attributeType.asClassType().name();\n                break;\n            case PARAMETERIZED_TYPE:\n                className = attributeType.name();\n                break;\n            default:\n                // do nothing\n                return;\n        }\n        if (validate && !index.getClassByName(className).hasAnnotation(ClassNames.EMBEDDABLE)) {\n            throw new BuildException(\n                    \"Type \" + className + \" must be annotated with @Embeddable, because it is used as an embeddable.\"\n                            + \" This type is used in class \" + declaringClass\n                            + \" for attribute \" + attribute + \".\");\n        }\n        embeddedTypes.add(attributeType.name());\n    }\n\n    private void collectElementCollectionTypes(Set<DotName> embeddedTypes, ClassInfo declaringClass,\n            Declaration attribute, Type attributeType)\n            throws BuildException {\n        switch (attributeType.kind()) {\n            case CLASS:\n                // Raw collection type, nothing we can do\n                break;\n            case PARAMETERIZED_TYPE:\n                embeddedTypes.add(attributeType.name());\n                var typeArguments = attributeType.asParameterizedType().arguments();\n                for (Type typeArgument : typeArguments) {","sourceCodeStart":566,"sourceCodeEnd":602,"githubUrl":"https://github.com/quarkusio/quarkus/blob/e1c734241f34c7919086ceb4c9262b4a58f6de44/extensions/hibernate-orm/deployment/src/main/java/io/quarkus/hibernate/orm/deployment/JpaJandexScavenger.java#L566-L602","documentation":"Quarkus validates at build time that any type used as an embeddable (via @Embedded, @EmbeddedId, or @ElementCollection on an embeddable type) is annotated with @Embeddable. If the target type lacks the annotation, a BuildException is thrown naming the type, declaring class, and attribute.","triggerScenarios":"collectEmbeddedType is invoked from enlistEmbeddedsAndElementCollections or collectElementCollectionTypes when an entity field annotated @Embedded/@EmbeddedId/@ElementCollection points to a type without @Embeddable in the Jandex index.","commonSituations":"Using an entity or plain POJO as an @Embedded field; forgetting @Embeddable when introducing an embeddable; the embeddable class present but not indexed; switching a field type from entity to embeddable without adding the annotation.","solutions":["Annotate the referenced type with jakarta.persistence.Embeddable","If the type should be its own entity, change the field mapping (remove @Embedded, use @OneToOne etc.)","If the type is in another module, ensure it is part of the application and indexed by Quarkus","Verify the attribute name and declaring class in the message to find the exact field to fix"],"exampleFix":"// before\npublic class Address { private String street; }\n@Entity public class Person { @Embedded Address address; }\n// after\n@Embeddable\npublic class Address { private String street; }\n@Entity public class Person { @Embedded Address address; }","handlingStrategy":"validation","validationCode":"// Check before mapping an @Embedded field\nstatic void requireEmbeddable(Class<?> type) {\n    if (!type.isAnnotationPresent(jakarta.persistence.Embeddable.class))\n        throw new IllegalArgumentException(type + \" must be @Embeddable\");\n}","typeGuard":"static boolean isEmbeddable(Class<?> t) {\n    return t.isAnnotationPresent(jakarta.persistence.Embeddable.class);\n}","tryCatchPattern":null,"preventionTips":["Always add @Embeddable to types used in @Embedded/@EmbeddedId/@ElementCollection fields","Add an ArchUnit/reflection test asserting embeddable usage is annotated","Distinguish entity vs embeddable types early in code review"],"tags":["quarkus","hibernate-orm","embeddable","build-time-validation"],"backgroundTag":"missing-embeddable-annotation","analyzedSha":"e1c734241f34c7919086ceb4c9262b4a58f6de44","analyzedAt":"2026-09-05T17:01:29.979Z","contentChangedAt":"2026-09-05T17:01:29.979Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}