apache/hadoop · error · MetricsException
Error setting field {} annotated with {}
Error message
Error setting field {} annotated with {} What it means
After building the MutableMetric for an @Metric-annotated field, MetricsSourceBuilder injects it with field.set(source, mutable). Any reflection failure at that assignment — most commonly a final field the builder cannot overwrite, or access blocked by security/module restrictions — is wrapped in MetricsException('Error setting field <field> annotated with <annotation>').
Source
Thrown at hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/metrics2/lib/MetricsSourceBuilder.java:154
continue;
}
try {
// skip fields already set
field.setAccessible(true);
if (field.get(source) != null) continue;
} catch (Exception e) {
LOG.warn("Error accessing field "+ field +" annotated with"+
annotation, e);
continue;
}
MutableMetric mutable = factory.newForField(field, (Metric) annotation,
registry);
if (mutable != null) {
try {
field.set(source, mutable); // Set the source field to MutableMetric
hasAtMetric = true;
} catch (Exception e) {
throw new MetricsException("Error setting field "+ field +
" annotated with "+ annotation, e);
}
}
}
}
/** Add {@link MutableMetric} for a method annotated with {@link Metric} */
private void add(Object source, Method method) {
for (Annotation annotation : method.getAnnotations()) {
if (!(annotation instanceof Metric)) {
continue;
}
factory.newForMethod(source, method, (Metric) annotation, registry);
hasAtMetric = true;
}
}
}
View on GitHub (pinned to 2add963021)
Solutions
- Remove final from @Metric-annotated fields so the builder can assign them
- Leave the field uninitialized (the builder creates and injects the MutableMetric)
- Ensure the class is reflectively accessible from the metrics2 code path (no security-manager denial)
Example fix
// before @Metric public final MutableGaugeLong size; // after @Metric public MutableGaugeLong size;
Defensive patterns
Strategy: validation
Validate before calling
for (Field f : cls.getDeclaredFields()) {
if (f.isAnnotationPresent(Metric.class) && Modifier.isFinal(f.getModifiers())) {
throw new IllegalStateException("@Metric field must not be final: " + f);
}
} Type guard
static boolean isInjectableMetricField(Field f) {
return f.isAnnotationPresent(Metric.class)
&& !Modifier.isFinal(f.getModifiers())
&& !Modifier.isStatic(f.getModifiers());
} Prevention
- Never mark @Metric fields final — the builder assigns them reflectively
- Leave @Metric fields uninitialized instead of assigning your own MutableMetric
- Add a reflection-based lint (isInjectableMetricField) to the build or test suite
When it happens
Trigger: Declaring @Metric on a final field (the builder must assign the MutableMetric into it), or on a field whose reflective write is disallowed in the runtime environment.
Common situations: Style habit of marking injected fields final; annotated fields that the developer also initializes themselves; restrictive security managers or module access rules around reflection.
Related errors
- Unsupported counter type: {}
- Unsupported gauge type: {}
- Unsupported tag type: {}
- Error creating plugin: {}
- Hybrid metrics: registry required.
AI-assisted analysis of apache/hadoop@2add963021 (2026-08-22).
Data as JSON: /api/errors/336a08f3738b1840.
Report an issue: GitHub.