{"record":{"id":"7d13d36d853bd7ac","repo":"apache/hadoop","slug":"unsupported-metric-field-of-type","errorCode":null,"errorMessage":"Unsupported metric field {} of type {}","messagePattern":"Unsupported metric field (.+?) of type (.+?)","errorType":"exception","errorClass":"MetricsException","httpStatus":null,"severity":"error","filePath":"hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/metrics2/lib/MutableMetricsFactory.java","lineNumber":90,"sourceCode":"      return new MutableRates(registry);\n    }\n    if (cls == MutableRatesWithAggregation.class) {\n      return registry.newRatesWithAggregation(info.name());\n    }\n    if (cls == MutableStat.class) {\n      return registry.newStat(info.name(), info.description(),\n                              annotation.sampleName(), annotation.valueName(),\n                              annotation.always());\n    }\n    if (cls == MutableRollingAverages.class) {\n      return registry.newMutableRollingAverages(info.name(),\n          annotation.valueName());\n    }\n    if (cls == MutableQuantiles.class) {\n      return registry.newQuantiles(info.name(), annotation.about(),\n          annotation.sampleName(), annotation.valueName(), annotation.interval());\n    }\n    throw new MetricsException(\"Unsupported metric field \"+ field.getName() +\n                               \" of type \"+ field.getType().getName());\n  }\n\n  MutableMetric newForMethod(Object source, Method method, Metric annotation,\n                             MetricsRegistry registry) {\n    if (LOG.isDebugEnabled()) {\n      LOG.debug(\"method \"+ method +\" with annotation \"+ annotation);\n    }\n    MetricsInfo info = getInfo(annotation, method);\n    MutableMetric metric = newForMethod(source, method, annotation);\n    metric = metric != null ? metric :\n        new MethodMetric(source, method, info, annotation.type());\n    registry.add(info.name(), metric);\n    return metric;\n  }\n\n  /**\n   * Override to handle custom mutable metrics for fields","sourceCodeStart":72,"sourceCodeEnd":108,"githubUrl":"https://github.com/apache/hadoop/blob/2add9630210752f88ceb1bb74eb65e37bf41da8e/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/metrics2/lib/MutableMetricsFactory.java#L72-L108","documentation":"When a metrics source class is initialized, Hadoop metrics2's MutableMetricsFactory reflectively scans every field annotated with @Metric and instantiates a Mutable metric based on the field's exact declared type. Only MutableCounterInt, MutableCounterLong, MutableGaugeInt, MutableGaugeLong, MutableGaugeFloat, MutableRate, MutableRates, MutableRatesWithAggregation, MutableStat, MutableRollingAverages and MutableQuantiles are recognized (matching is exact Class equality). Any other declared type falls through to this MetricsException, naming the offending field and its type, and fails source registration at startup.","triggerScenarios":"Declaring @Metric on a field whose type is not in the supported list: @Metric MutableMetric requests; @Metric int counter; or @Metric on a custom MutableMetric subclass (exact class comparison means subclasses do NOT match). Thrown from newForField during MetricsSystem.register() or annotation-driven init of a @Metrics class.","commonSituations":"Writing a custom MetricsSource and declaring the interface type instead of a concrete class; porting code between Hadoop versions where a Mutable* type (e.g. MutableQuantiles, MutableRollingAverages, MutableRatesWithAggregation) does not exist so a hand-written stand-in is used; importing a same-named class from another package so the Class identity check fails.","solutions":["Change the field's declared type to a supported class, e.g. MutableCounterLong, MutableGaugeLong, MutableStat, MutableRate, MutableQuantiles or MutableRollingAverages","For a genuinely custom metric type, override MutableMetricsFactory#newForField(Field, Metric) (the hook exists exactly for custom mutable metrics) instead of relying on the type map","If the registry pattern is not needed, implement MetricsSource directly and emit MetricsRecords without @Metric fields"],"exampleFix":"// before\n@Metrics(about=\"Job metrics\", context=\"myjob\")\npublic class MyMetrics {\n  @Metric MutableMetric requests; // Unsupported metric field requests of type ...\n}\n\n// after\n@Metrics(about=\"Job metrics\", context=\"myjob\")\npublic class MyMetrics {\n  @Metric MutableCounterLong requests;\n}","handlingStrategy":"type-guard","validationCode":"Set<Class<?>> SUPPORTED = new HashSet<>(Arrays.asList(\n    MutableCounterInt.class, MutableCounterLong.class,\n    MutableGaugeInt.class, MutableGaugeLong.class, MutableGaugeFloat.class,\n    MutableRate.class, MutableRates.class, MutableRatesWithAggregation.class,\n    MutableStat.class, MutableRollingAverages.class, MutableQuantiles.class));\nfor (Field f : MyMetrics.class.getDeclaredFields()) {\n  if (f.isAnnotationPresent(Metric.class) && !SUPPORTED.contains(f.getType())) {\n    throw new IllegalStateException(\"Bad @Metric field \" + f.getName()\n        + \" of type \" + f.getType().getName());\n  }\n}","typeGuard":"static boolean isSupportedMetricField(Field f) {\n  if (!f.isAnnotationPresent(Metric.class)) return true;\n  Class<?> t = f.getType();\n  return t == MutableCounterInt.class || t == MutableCounterLong.class\n      || t == MutableGaugeInt.class || t == MutableGaugeLong.class\n      || t == MutableGaugeFloat.class || t == MutableRate.class\n      || t == MutableRates.class || t == MutableRatesWithAggregation.class\n      || t == MutableStat.class || t == MutableRollingAverages.class\n      || t == MutableQuantiles.class;\n}","tryCatchPattern":"try {\n  metricsSystem.register(\"myjob\", \"My job metrics\", new MyMetrics());\n} catch (MetricsException e) {\n  // message names the exact unsupported field and its type\n  throw new IllegalStateException(\"Metrics source registration failed: \" + e.getMessage(), e);\n}","preventionTips":["Always declare @Metric fields with a concrete supported Mutable* class, never MutableMetric or a custom subclass","Import Mutable types only from org.apache.hadoop.hadoop.metrics2.lib — same-named classes elsewhere fail the exact Class comparison","Add a unit test that instantiates every @Metrics-annotated class so unsupported fields fail in CI, not at daemon startup"],"tags":["metrics2","hadoop","metric-annotation","reflection","type-mismatch"],"backgroundTag":"unsupported-type","analyzedSha":"2add9630210752f88ceb1bb74eb65e37bf41da8e","analyzedAt":"2026-08-22T19:55:07.957Z","schemaVersion":2},"datasetVersion":"2026-08-22T20:17:22.307Z"}