{"record":{"id":"a18972433207c648","repo":"theonedev/onedev","slug":"dependency-property-not-found-property","errorCode":null,"errorMessage":"Dependency property not found: ${property}","messagePattern":"Dependency property not found: (.+?)","errorType":"exception","errorClass":"ExplicitException","httpStatus":null,"severity":"error","filePath":"server-core/src/main/java/io/onedev/server/web/editable/PropertyDescriptor.java","lineNumber":177,"sourceCode":"\t\t\n\t\tSet<String> prevDependencyPropertyNames = new HashSet<>(getDependencyPropertyNames());\n\t\tvar hierarchicalContext = hierarchicalContexts.get(getPropertyName());\n\t\tif (hierarchicalContext != null)\n\t\t\tHierarchicalContext.push(hierarchicalContext);\n\t\ttry {\n\t\t\t/* \n\t\t\t * Sometimes, the dependency may include properties introduced while evaluating available choices \n\t\t\t * of a choice input. We clear it temporarily here in order to make visibility of the property \n\t\t\t * consistent of BeanViewer, Issue.isFieldVisible, or Build.isParamVisible \n\t\t\t */\n\t\t\tgetDependencyPropertyNames().clear();\n\t\t\tShowCondition showCondition = getPropertyGetter().getAnnotation(ShowCondition.class);\n\t\t\tif (showCondition != null && !(boolean)ReflectionUtils.invokeStaticMethod(getBeanClass(), showCondition.value()))\n\t\t\t\treturn false;\n\t\t\tfor (DependsOn dependsOn : getPropertyGetter().getAnnotationsByType(DependsOn.class)) {\n\t\t\t\tvar dependencyProperty = beanDescriptor.getProperty(dependsOn.property());\n\t\t\t\tif (dependencyProperty == null) {\n\t\t\t\t\tthrow new ExplicitException(\"Dependency property not found: \" + dependsOn.property());\n\t\t\t\t}\n\t\t\t\tvar dependencyPropertyValue = EditContext.get().getInputValue(dependsOn.property());\t\n\t\t\t\tif (!DependsOnUtils.isPropertyVisible(dependsOn, dependencyProperty.getPropertyClass(), dependencyPropertyValue))\t\t\t\n\t\t\t\t\treturn false;\n\t\t\t}\n\t\t\tgetDependencyPropertyNames().remove(getPropertyName());\n\t\t\tfor (String dependencyPropertyName: getDependencyPropertyNames()) {\n\t\t\t\tSet<String> copyOfCheckedPropertyNames = new HashSet<>(checkedPropertyNames);\n\t\t\t\tif (!beanDescriptor.getProperty(dependencyPropertyName).isPropertyVisible(hierarchicalContexts, beanDescriptor, copyOfCheckedPropertyNames))\n\t\t\t\t\treturn false;\n\t\t\t}\n\t\t\treturn true;\n\t\t} finally {\n\t\t\tgetDependencyPropertyNames().addAll(prevDependencyPropertyNames);\n\t\t\tif (hierarchicalContext != null)\n\t\t\t\tHierarchicalContext.pop();\n\t\t}\n\t}","sourceCodeStart":159,"sourceCodeEnd":195,"githubUrl":"https://github.com/theonedev/onedev/blob/d44925c47c37992c828ea673a5f9620539bc3ff2/server-core/src/main/java/io/onedev/server/web/editable/PropertyDescriptor.java#L159-L195","documentation":"PropertyDescriptor.isPropertyVisible evaluates @DependsOn annotations on a bean property. For each DependsOn, it looks up the referenced dependency property in the bean's BeanDescriptor; if that property does not exist, it throws this ExplicitException instead of silently treating the property as visible/invisible. This catches broken @DependsOn(property=\"...\") references at edit-form render time.","triggerScenarios":"A property annotated @DependsOn(property=\"X\") (possibly repeated) where no property named X exists on the same bean class — e.g. a typo in the annotation, X was renamed/removed, or X lives on a different (parent/child) bean.","commonSituations":"Writing a custom job/issue/build parameter class with @DependsOn; refactoring a bean and renaming a field without updating @DependsOn annotations; upgrading OneDev where a dependency field name changed.","solutions":["Check every @DependsOn(property=\"...\") on the failing property and correct the name to an existing property on the same bean.","After refactors, grep for DependsOn annotations referencing renamed/deleted fields and update them.","Ensure the dependency property is declared on the same class (not a different nesting level of the edit form).","Rebuild/redeploy after fixing so the edited class is loaded."],"exampleFix":"// before\n@DependsOn(property=\"envVarible\")\n@Editable(name=\"Value\")\npublic String getValue() { ... }\n// after\n@DependsOn(property=\"envVariable\")\n@Editable(name=\"Value\")\npublic String getValue() { ... }","handlingStrategy":"validation","validationCode":"// at class-load/test time, validate all @DependsOn references\nfor (PropertyDescriptor pd : new BeanDescriptor(MyBean.class).getProperties()) {\n    for (DependsOn d : pd.getPropertyGetter().getAnnotationsByType(DependsOn.class)) {\n        if (new BeanDescriptor(MyBean.class).getProperty(d.property()) == null)\n            throw new IllegalStateException(\"@DependsOn references missing property: \" + d.property());\n    }\n}","typeGuard":null,"tryCatchPattern":"try {\n    boolean visible = propertyDescriptor.isPropertyVisible(...);\n} catch (ExplicitException e) {\n    log.error(\"Broken @DependsOn on property {}: {}\", propertyDescriptor.getPropertyName(), e.getMessage());\n    throw e; // fix the annotation; visibility cannot be defaulted safely\n}","preventionTips":["When renaming a bean property, always grep the class for @DependsOn referencing the old name.","Keep @DependsOn property names next to the annotated property with a comment linking both fields.","Add a unit test that instantiates the BeanDescriptor for parameter classes to catch broken dependency references early.","Only depend on properties declared in the same bean class."],"tags":["annotation","beans","depends-on","onedev"],"backgroundTag":"record-not-found","analyzedSha":"d44925c47c37992c828ea673a5f9620539bc3ff2","analyzedAt":"2026-09-06T07:18:27.995Z","contentChangedAt":"2026-09-06T07:18:27.995Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}