{"record":{"id":"19ed8f1a761cfc4c","repo":"theonedev/onedev","slug":"property-type-is-reserved-class-classname","errorCode":null,"errorMessage":"Property 'type' is reserved (class: <className>)","messagePattern":"Property 'type' is reserved \\(class: <className>\\)","errorType":"validation","errorClass":"ExplicitException","httpStatus":null,"severity":"error","filePath":"server-core/src/main/java/io/onedev/server/data/migration/VersionedYamlDoc.java","lineNumber":232,"sourceCode":"\t\t\t        }\n\t\t\t    }\n\n\t\t\t};\n\t\t\trepresenter.setDefaultFlowStyle(FlowStyle.BLOCK);\n\t\t\trepresenter.setPropertyUtils(new PropertyUtils() {\n\n\t\t\t\t@Override\n\t\t\t\tprotected Set<Property> createPropertySet(Class<? extends Object> type, BeanAccess bAccess) {\n\t\t\t\t\tList<Property> properties = new ArrayList<>();\n\t\t\t\t\tMap<String, Integer> orders = new HashMap<>();\n\t\t\t\t\tif (type.getAnnotation(Editable.class) != null) {\n\t\t\t\t\t\tfor (Method getter: BeanUtils.findGetters(type)) {\n\t\t\t\t\t\t\tEditable editable = getter.getAnnotation(Editable.class);\n\t\t\t\t\t\t\tMethod setter = BeanUtils.findSetter(getter);\n\t\t\t\t\t\t\tif (editable != null && setter != null) {\n\t\t\t\t\t\t\t\tString propertyName = BeanUtils.getPropertyName(getter);\n\t\t\t\t\t\t\t\tif (propertyName.equals(\"type\"))\n\t\t\t\t\t\t\t\t\tthrow new ExplicitException(\"Property 'type' is reserved (class: \" + type.getName() + \")\");\n\t\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\t\tproperties.add(new MethodProperty(new PropertyDescriptor(propertyName, getter, setter)));\n\t\t\t\t\t\t\t\t} catch (IntrospectionException e) {\n\t\t\t\t\t\t\t\t\tthrow new RuntimeException(e);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\torders.put(propertyName, editable.order());\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tCollections.sort(properties, new Comparator<Property>() {\n\n\t\t\t\t\t\t@Override\n\t\t\t\t\t\tpublic int compare(Property o1, Property o2) {\n\t\t\t\t\t\t\treturn orders.get(o1.getName()) - orders.get(o2.getName());\n\t\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t\t});\n\t\t\t\t\treturn new LinkedHashSet<>(properties);","sourceCodeStart":214,"sourceCodeEnd":250,"githubUrl":"https://github.com/theonedev/onedev/blob/d44925c47c37992c828ea673a5f9620539bc3ff2/server-core/src/main/java/io/onedev/server/data/migration/VersionedYamlDoc.java#L214-L250","documentation":"During YAML data migration, VersionedYamlDoc builds a property set from a class's @Editable getters and setters. A bean property named 'type' is disallowed because 'type' is used internally in the versioned YAML document format to record the class name. Any persistable class exposing a getter/setter pair named 'type' aborts the migration/deserialization with this ExplicitException.","triggerScenarios":"Persisting (via versioned YAML) a class that has an @Editable getter named getType() with a matching setter; e.g. adding a field named 'type' to a data entity or migration DTO.","commonSituations":"Renaming an enum-like discriminator field to 'type' on a persisted entity; copying POJO patterns from other frameworks where 'type' is a natural field name; old migrations failing after a new field was introduced.","solutions":["Rename the bean property from 'type' to something else (e.g. 'typeName' or 'itemType').","If 'type' must not be persisted, remove it from the bean or drop the @Editable annotation / setter so it is excluded from the property set.","If the field is required for new data, add a migration step converting old YAML docs that used 'type'.","Check whether the bean is actually meant to participate in versioned YAML persistence; exclude it if not."],"exampleFix":"// before\n@Editable\npublic String getType() { return type; }\npublic void setType(String type) { this.type = type; }\n// after\n@Editable\npublic String getItemType() { return itemType; }\npublic void setItemType(String itemType) { this.itemType = itemType; }","handlingStrategy":"validation","validationCode":"for (Method getter : BeanUtils.findGetters(type)) {\n    if (BeanUtils.getPropertyName(getter).equals(\"type\"))\n        throw new IllegalStateException(type.getName() + \" must not define a bean property named 'type'\");\n}","typeGuard":"boolean hasReservedTypeProperty(Class<?> type) {\n    return BeanUtils.findGetters(type).stream()\n        .anyMatch(g -> BeanUtils.getPropertyName(g).equals(\"type\"));\n}","tryCatchPattern":"try {\n    doc.createPropertySet();\n} catch (ExplicitException e) {\n    log.error(\"Bean violates versioned YAML constraints: \" + e.getMessage());\n    throw new ConfigurationException(e.getMessage());\n}","preventionTips":["Never name a persisted bean property 'type' in classes serialized with VersionedYamlDoc.","Add a unit test that round-trips persistable classes through VersionedYamlDoc.","Prefer names like itemType, typeName, kind for discriminator fields.","Check for reserved property names when introducing new entities used in migrations."],"tags":["yaml","migration","serialization","naming-conflict"],"backgroundTag":"invalid-identifier","analyzedSha":"d44925c47c37992c828ea673a5f9620539bc3ff2","analyzedAt":"2026-09-06T07:18:27.995Z","contentChangedAt":"2026-09-06T07:18:27.995Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}