{"record":{"id":"82fd807cf097e5bc","repo":"apache/hadoop","slug":"unsupported-counter-type","errorCode":null,"errorMessage":"Unsupported counter type: {}","messagePattern":"Unsupported counter type: (.+?)","errorType":"exception","errorClass":"MetricsException","httpStatus":null,"severity":"error","filePath":"hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/metrics2/lib/MethodMetric.java","lineNumber":86,"sourceCode":"        return null;\n    }\n  }\n\n  MutableMetric newCounter(final Class<?> type) {\n    if (isInt(type) || isLong(type)) {\n      return new MutableMetric() {\n        @Override public void snapshot(MetricsRecordBuilder rb, boolean all) {\n          try {\n            Object ret = method.invoke(obj, (Object[])null);\n            if (isInt(type)) rb.addCounter(info, ((Integer) ret).intValue());\n            else rb.addCounter(info, ((Long) ret).longValue());\n          } catch (Exception ex) {\n            LOG.error(\"Error invoking method \"+ method.getName(), ex);\n          }\n        }\n      };\n    }\n    throw new MetricsException(\"Unsupported counter type: \"+ type.getName());\n  }\n\n  static boolean isInt(Class<?> type) {\n    boolean ret = type == Integer.TYPE || type == Integer.class;\n    return ret;\n  }\n\n  static boolean isLong(Class<?> type) {\n    return type == Long.TYPE || type == Long.class;\n  }\n\n  static boolean isFloat(Class<?> type) {\n    return type == Float.TYPE || type == Float.class;\n  }\n\n  static boolean isDouble(Class<?> type) {\n    return type == Double.TYPE || type == Double.class;\n  }","sourceCodeStart":68,"sourceCodeEnd":104,"githubUrl":"https://github.com/apache/hadoop/blob/2add9630210752f88ceb1bb74eb65e37bf41da8e/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/metrics2/lib/MethodMetric.java#L68-L104","documentation":"MethodMetric.newCounter builds the implementation for an @Metric-annotated method with type COUNTER; only int/Integer and long/Long return types are supported. Any other return type falls through to MetricsException('Unsupported counter type: <class name>').","triggerScenarios":"@Metric(type=Type.COUNTER) on a method returning double, float, String, Boolean, or any type other than int/Integer/long/Long — MetricsSourceBuilder scans methods and delegates each to MethodMetric.","commonSituations":"Copy-pasting a gauge method (double) and flipping the annotation to COUNTER; refactoring a counter method's return type without updating the annotation; annotated methods returning boxed or custom types.","solutions":["Change the method's return type to int or long","If the value is genuinely fractional, keep the metric a GAUGE instead of COUNTER","Move the counter to an annotated MutableCounterLong field instead of a method"],"exampleFix":"// before\n@Metric(type=Type.COUNTER)\npublic double filesRead() { return total; }\n\n// after\n@Metric(type=Type.COUNTER)\npublic long filesRead() { return total; }","handlingStrategy":"type-guard","validationCode":"for (Method m : cls.getDeclaredMethods()) {\n  Metric ann = m.getAnnotation(Metric.class);\n  if (ann != null && ann.type() == Type.COUNTER && !isCounterType(m.getReturnType())) {\n    throw new IllegalStateException(\"@Metric COUNTER on non-int/long method: \" + m);\n  }\n}","typeGuard":"static boolean isCounterType(Class<?> t) {\n  return t == int.class || t == Integer.class\n      || t == long.class || t == Long.class;\n}","tryCatchPattern":"try {\n  new MetricsSourceBuilder(obj, \"MyMetrics\").build();\n} catch (MetricsException e) {\n  // check annotated method return types against isCounterType before build to avoid this\n  throw e;\n}","preventionTips":["Keep counter methods int/long only; convert doubles before returning","Add a startup unit test that scans @Metric COUNTER methods with isCounterType","Prefer @Metric on MutableCounterLong fields over methods for counters"],"tags":["metrics2","hadoop","annotation","type-mismatch","reflection"],"backgroundTag":"unsupported-metric-return-type","analyzedSha":"2add9630210752f88ceb1bb74eb65e37bf41da8e","analyzedAt":"2026-08-22T19:55:07.957Z","schemaVersion":2},"datasetVersion":"2026-08-23T01:17:44.959Z"}