{"record":{"id":"a049b3b2daa77768","repo":"spring-projects/spring-framework","slug":"value-annotation-must-have-a-value-attribute","errorCode":null,"errorMessage":"Value annotation must have a value attribute","messagePattern":"Value annotation must have a value attribute","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"spring-beans/src/main/java/org/springframework/beans/factory/annotation/QualifierAnnotationAutowireCandidateResolver.java","lineNumber":443,"sourceCode":"\tprotected @Nullable Object findValue(Annotation[] annotationsToSearch) {\n\t\tif (annotationsToSearch.length > 0) {   // qualifier annotations have to be local\n\t\t\tAnnotationAttributes attr = AnnotatedElementUtils.getMergedAnnotationAttributes(\n\t\t\t\t\tAnnotatedElementUtils.forAnnotations(annotationsToSearch), this.valueAnnotationType);\n\t\t\tif (attr != null) {\n\t\t\t\treturn extractValue(attr);\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n\t/**\n\t * Extract the value attribute from the given annotation.\n\t * @since 4.3\n\t */\n\tprotected Object extractValue(AnnotationAttributes attr) {\n\t\tObject value = attr.get(AnnotationUtils.VALUE);\n\t\tif (value == null) {\n\t\t\tthrow new IllegalStateException(\"Value annotation must have a value attribute\");\n\t\t}\n\t\treturn value;\n\t}\n\n}\n","sourceCodeStart":425,"sourceCodeEnd":449,"githubUrl":"https://github.com/spring-projects/spring-framework/blob/69bf83ad716d0cfc4b0520a19b4d8b24c79d1538/spring-beans/src/main/java/org/springframework/beans/factory/annotation/QualifierAnnotationAutowireCandidateResolver.java#L425-L449","documentation":"Thrown by QualifierAnnotationAutowireCandidateResolver.extractValue() when a value-annotation (used for @Value-style expression resolution) is found but has no attribute named 'value'. Spring's suggested-value resolution looks for a 'value' attribute on the annotation (configured via setValueAnnotationType, defaults to Value.class). If the annotation lacks this attribute, the resolver cannot extract the expression string.","triggerScenarios":"Configuring a custom value annotation type (via setValueAnnotationType) that does not declare a 'value' attribute. The findValue() method at line 425-433 successfully finds merged annotation attributes for the value annotation type, but extractValue() finds no 'value' key in the attributes.","commonSituations":"Setting a custom annotation as the valueAnnotationType that has attributes named differently (e.g., 'expression' instead of 'value'). Subclassing QualifierAnnotationAutowireCandidateResolver and overriding setValueAnnotationType with a non-standard annotation. Framework integration where a custom value annotation lacks the conventional 'value' attribute.","solutions":["Ensure the custom value annotation type declares a 'value' attribute (the conventional name Spring expects).","If using @Value (the default), verify it is from the correct package (org.springframework.beans.factory.annotation.Value) which has the value attribute.","If your annotation uses a different attribute name, override findValue()/extractValue() in a subclass to extract from the correct attribute."],"exampleFix":"// before\n// Custom annotation without 'value' attribute\n@Retention(RetentionPolicy.RUNTIME)\npublic @interface MyValue {\n    String expression(); // wrong attribute name\n}\n\n// after\n@Retention(RetentionPolicy.RUNTIME)\npublic @interface MyValue {\n    String value(); // matches what Spring expects\n}","handlingStrategy":"validation","validationCode":"// Verify the value annotation type has a 'value' attribute\nClass<? extends Annotation> valueAnnotationType = MyValue.class;\ntry {\n    valueAnnotationType.getDeclaredMethod(\"value\");\n    // 'value' attribute exists — safe to use\n} catch (NoSuchMethodException e) {\n    throw new IllegalStateException(\n        valueAnnotationType + \" must declare a 'value' attribute\");\n}","typeGuard":"// Type guard: check that an annotation type has a 'value' attribute\nstatic boolean hasValueAttribute(Class<? extends Annotation> type) {\n    try {\n        type.getDeclaredMethod(\"value\");\n        return true;\n    } catch (NoSuchMethodException e) {\n        return false;\n    }\n}","tryCatchPattern":null,"preventionTips":["Custom value annotation types must declare a 'value' attribute matching Spring's convention.","Use org.springframework.beans.factory.annotation.Value directly instead of a custom value annotation unless necessary.","Test custom value annotations before deploying them in QualifierAnnotationAutowireCandidateResolver."],"tags":["spring","qualifier","value-annotation","configuration"],"backgroundTag":null,"analyzedSha":"69bf83ad716d0cfc4b0520a19b4d8b24c79d1538","analyzedAt":"2026-08-09T15:32:58.770Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}