grpc/grpc-java · error · IllegalStateException

Metric with name ${name} already exists

Error message

Metric with name ${name} already exists

What it means

MetricInstrumentRegistry.registerDoubleCounter registers a double counter metric instrument by unique name in a process-wide registry. Registering the same name twice throws IllegalStateException('Metric with name X already exists') to prevent conflicting definitions (labels/units) for one metric name.

Source

Thrown at api/src/main/java/io/grpc/MetricInstrumentRegistry.java:92

   * @param description a description of the metric
   * @param unit the unit of measurement for the metric
   * @param requiredLabelKeys a list of required label keys
   * @param optionalLabelKeys a list of optional label keys
   * @param enableByDefault whether the metric should be enabled by default
   * @return the newly created DoubleCounterMetricInstrument
   * @throws IllegalStateException if a metric with the same name already exists
   */
  public DoubleCounterMetricInstrument registerDoubleCounter(String name,
      String description, String unit, List<String> requiredLabelKeys,
      List<String> optionalLabelKeys, boolean enableByDefault) {
    checkArgument(!Strings.isNullOrEmpty(name), "missing metric name");
    checkNotNull(description, "description");
    checkNotNull(unit, "unit");
    checkNotNull(requiredLabelKeys, "requiredLabelKeys");
    checkNotNull(optionalLabelKeys, "optionalLabelKeys");
    synchronized (lock) {
      if (registeredMetricNames.contains(name)) {
        throw new IllegalStateException("Metric with name " + name + " already exists");
      }
      int index = nextAvailableMetricIndex;
      if (index + 1 == metricInstruments.length) {
        resizeMetricInstruments();
      }
      // TODO(dnvindhya): add limit for number of optional labels allowed
      DoubleCounterMetricInstrument instrument = new DoubleCounterMetricInstrument(
          index, name, description, unit, requiredLabelKeys, optionalLabelKeys,
          enableByDefault);
      metricInstruments[index] = instrument;
      registeredMetricNames.add(name);
      nextAvailableMetricIndex += 1;
      return instrument;
    }
  }

  /**
   * Registers a new Long Counter metric instrument.

View on GitHub (pinned to 64daddc1f3)

Solutions

  1. Guard registration so it runs once per JVM (static init flag, singleton init)
  2. Check name existence before registering, or dedupe metric names across libraries
  3. In app servers, ensure the registry lifecycle is tied to the webapp classloader
  4. Rename the metric if a genuine collision with another library exists

Example fix

// before
registry.registerDoubleCounter("rpc.duration", desc, unit, labels, optionalLabels);
// after
if (!registered) {
  registry.registerDoubleCounter("rpc.duration", desc, unit, labels, optionalLabels);
  registered = true;
}
Defensive patterns

Strategy: try-catch

Validate before calling

// no public pre-check API in older versions; guard at call site
if (alreadyRegistered("rpc.duration")) return; // track your own registration set

Try / catch

try {
  registry.registerDoubleCounter(name, desc, unit, labelKeys, optionalLabelKeys);
} catch (IllegalStateException e) {
  // duplicate metric name: log and continue if definition is identical
}

Prevention

When it happens

Trigger: Calling registerDoubleCounter twice with the same metric name — typically during repeated SDK/library initialization, multiple registry instances sharing names, or classloader re-initialization within one JVM.

Common situations: Calling grpc initialization code twice (e.g. both app code and a framework plugin init metrics); hot redeploys in an app server that does not release the old registry; two versions of a library both registering the same metric name.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


AI-assisted analysis of grpc/grpc-java@64daddc1f3 (2026-09-08). Data as JSON: /api/errors/5ce0a87572533dfe. Report an issue: GitHub.