{"record":{"id":"218f6ea93efaca35","repo":"hibernate/hibernate-orm","slug":"enhancement-of-s-failed-because-no-underlying-f","errorCode":null,"errorMessage":"Enhancement of [%s] failed because no underlying field named [%s] exists for property accessor method [%s] (ensure all property accessor methods have a matching field)","messagePattern":"Enhancement of \\[(.+?)\\] failed because no underlying field named \\[(.+?)\\] exists for property accessor method \\[(.+?)\\] \\(ensure all property accessor methods have a matching field\\)","errorType":"exception","errorClass":"EnhancementException","httpStatus":null,"severity":"error","filePath":"hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/bytebuddy/EnhancerImpl.java","lineNumber":716,"sourceCode":"\t\treturn false;\n\t}\n\n\t@SuppressWarnings(\"deprecation\")\n\tprivate static boolean handleMissingField(\n\t\t\tTypeDescription managedCtClass,\n\t\t\tUnsupportedEnhancementStrategy strategy,\n\t\t\tMethodDescription methodDescription,\n\t\t\tString fieldName) {\n\t\treturn switch ( strategy ) {\n\t\t\tcase SKIP -> {\n\t\t\t\tENHANCEMENT_LOGGER.propertyAccessorNoFieldSkip(\n\t\t\t\t\t\tmanagedCtClass.getName(),\n\t\t\t\t\t\tfieldName,\n\t\t\t\t\t\tmethodDescription.getName()\n\t\t\t\t);\n\t\t\t\tyield true;\n\t\t\t}\n\t\t\tcase FAIL -> throw new EnhancementException( String.format(\n\t\t\t\t\t\"Enhancement of [%s] failed because no underlying field named [%s] exists for property accessor method [%s]\"\n\t\t\t\t\t+ \" (ensure all property accessor methods have a matching field)\",\n\t\t\t\t\tmanagedCtClass.getName(),\n\t\t\t\t\tfieldName,\n\t\t\t\t\tmethodDescription.getName()\n\t\t\t) );\n\t\t\tcase LEGACY -> throw new AssertionFailure( \"Unexpected strategy at this point: \" + strategy );\n\t\t};\n\t}\n\n\tprivate static @Nullable String propertyName(MethodDescription methodDescription) {\n\t\treturn getJavaBeansFieldName( trimGetterName( methodDescription.getActualName() ) );\n\t}\n\n\tprivate static @Nonnull String trimGetterName(String methodName) {\n\t\tif ( methodName.startsWith( \"get\" ) || methodName.startsWith( \"set\" ) ) {\n\t\t\treturn methodName.substring( 3 );\n\t\t}","sourceCodeStart":698,"sourceCodeEnd":734,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/bytebuddy/EnhancerImpl.java#L698-L734","documentation":"During enhancement Hibernate treats JavaBeans-style accessors (get/set/is methods) as property accessors and expects a backing field of the derived name. When no such field exists, behavior depends on the UnsupportedEnhancementStrategy: SKIP logs propertyAccessorNoFieldSkip and moves on, but FAIL (the case here) throws EnhancementException telling you which class/accessor lacked the field - the method looks like an accessor but there is nothing to instrument.","triggerScenarios":"An entity (or extended-enhancement target) has a method named like a getter/setter (getTotal(), isValid(), setName(...)) with no corresponding field 'total'/'valid'/'name' - computed or delegated properties - while the enhancement strategy is FAIL.","commonSituations":"DTO-like entities with calculated getters; lombok @Getter on a parent interface; methods delegating to a wrapped object; renaming a field without renaming its accessor (or vice versa) during a refactor; boolean 'isXxx' naming where the field is 'xxxFix' style.","solutions":["Rename the method so it no longer matches the JavaBeans accessor pattern (e.g. computeTotal(), nameOf()) - Hibernate then ignores it during enhancement.","Add the matching field the accessor exposes, so instrumentation has something to attach to.","Configure the unsupported-enhancement strategy to SKIP so these methods are logged (propertyAccessorNoFieldSkip) and enhancement continues instead of failing.","Audit with the message's triple (class, fieldName, methodName): propertyName() derives the field name from the method name, so the mismatch is usually visible immediately."],"exampleFix":"// before\npublic class Invoice {\n    public BigDecimal getTotal() { return lines.stream().map(Line::getAmt).reduce(ZERO, ADD); }\n    // no field 'total' -> EnhancementException with strategy FAIL\n}\n\n// after\npublic class Invoice {\n    public BigDecimal computeTotal() { return lines.stream().map(Line::getAmt).reduce(ZERO, ADD); }\n}","handlingStrategy":"fallback","validationCode":"// before enhancement, flag accessor-named methods without backing fields\nfor ( var m : entityClass.getDeclaredMethods() ) {\n    java.util.Optional<String> field = javaBeansFieldOf( m.getName() ); // getFoo/isFoo/setFoo -> foo\n    if ( field.isPresent() && java.util.Arrays.stream( entityClass.getDeclaredFields() )\n            .noneMatch( f -> f.getName().equals( field.get() ) ) ) {\n        issues.add( entityClass.getName() + \"#\" + m.getName() + \" has no field \" + field.get() );\n    }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Avoid JavaBeans accessor names (get*/set*/is*) for computed or delegated methods on enhanced classes.","Keep field names and accessor names exactly aligned in code review and refactors.","Configure the unsupported-enhancement strategy to SKIP for classes where accessor-like helpers are intentional."],"tags":["hibernate","bytecode-enhancement","javabeans","accessor","naming"],"backgroundTag":"accessor-without-backing-field","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}