apache/hadoop · error · MetricsException

Hybrid metrics: registry required.

Error message

Hybrid metrics: registry required.

What it means

MetricsSourceBuilder.build() supports 'hybrid' sources: objects that implement MetricsSource but also carry @Metric-annotated members. Those members are wired through a MetricsRegistry field on the class; if @Metric members exist but no MetricsRegistry field does, build() throws MetricsException('Hybrid metrics: registry required.').

Source

Thrown at hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/metrics2/lib/MetricsSourceBuilder.java:79

  MetricsSourceBuilder(Object source, MutableMetricsFactory factory) {
    this.source = checkNotNull(source, "source");
    this.factory = checkNotNull(factory, "mutable metrics factory");
    Class<?> cls = source.getClass();
    registry = initRegistry(source);

    for (Field field : ReflectionUtils.getDeclaredFieldsIncludingInherited(cls)) {
      add(source, field);
    }
    for (Method method : ReflectionUtils.getDeclaredMethodsIncludingInherited(cls)) {
      add(source, method);
    }
  }

  public MetricsSource build() {
    if (source instanceof MetricsSource) {
      if (hasAtMetric && !hasRegistry) {
        throw new MetricsException("Hybrid metrics: registry required.");
      }
      return (MetricsSource) source;
    }
    else if (!hasAtMetric) {
      throw new MetricsException("No valid @Metric annotation found.");
    }
    return new MetricsSource() {
      @Override
      public void getMetrics(MetricsCollector builder, boolean all) {
        registry.snapshot(builder.addRecord(registry.info()), all);
      }
    };
  }

  public MetricsInfo info() {
    return info;
  }

View on GitHub (pinned to 2add963021)

Solutions

  1. Add a MetricsRegistry field (private final MetricsRegistry registry = new MetricsRegistry(...)) and snapshot it inside getMetrics
  2. Drop the @Metric annotations if getMetrics is fully custom
  3. Move the annotated members into a separate registry-based class and register that instead

Example fix

// before
class MySource implements MetricsSource {
  @Metric public MutableGaugeLong size;
  public void getMetrics(MetricsCollector c, boolean all) { /* custom */ }
}

// after
class MySource implements MetricsSource {
  private final MetricsRegistry registry = new MetricsRegistry("MySource");
  @Metric public MutableGaugeLong size;
  public void getMetrics(MetricsCollector c, boolean all) {
    registry.snapshot(c.addRecord(registry.info()), all);
  }
}
Defensive patterns

Strategy: validation

Validate before calling

static void assertHybridSourceValid(Class<?> cls) {
  boolean hasMetric = Arrays.stream(cls.getDeclaredFields())
      .anyMatch(f -> f.isAnnotationPresent(Metric.class));
  boolean hasRegistry = Arrays.stream(cls.getDeclaredFields())
      .anyMatch(f -> MetricsRegistry.class.isAssignableFrom(f.getType()));
  if (MetricsSource.class.isAssignableFrom(cls) && hasMetric && !hasRegistry) {
    throw new IllegalStateException("hybrid metrics source needs a MetricsRegistry field");
  }
}

Prevention

When it happens

Trigger: A class implements MetricsSource (custom getMetrics) and declares @Metric-annotated fields or methods, but has no MetricsRegistry field for the builder to populate and snapshot.

Common situations: Evolving a hand-written source by adding @Metric convenience members; merging a registry-based metrics class into an existing MetricsSource implementation.

Related errors


AI-assisted analysis of apache/hadoop@2add963021 (2026-08-22). Data as JSON: /api/errors/429138b6703f8c31. Report an issue: GitHub.