nathanmarz/storm · error · RuntimeException

The same metric name

Error message

The same metric name `${name}` was registered twice.

What it means

registerMetric stores metrics per time-bucket and per task id, and each metric name must be unique within a task. Registering two metrics with the same name for the same task throws this RuntimeException to prevent silent metric collision/overwriting in the metrics consumers.

Solutions

  1. Use unique, descriptive names for every metric (e.g. prefix with component/purpose).
  2. Guard registration with a flag or check so it executes exactly once per task.
  3. Differentiate metrics registered in loops by appending the loop key to the name.
  4. On re-prepare (e.g. after reload), skip registration if the metric already exists — reuse the instance.

Example fix

// before
context.registerMetric("count", new CountMetric(), 10);
// later, same task:
context.registerMetric("count", new CountMetric(), 10); // throws

// after
context.registerMetric("spout-emit-count", new CountMetric(), 10);
context.registerMetric("bolt-ack-count", new CountMetric(), 10);
Defensive patterns

Strategy: validation

Validate before calling

Set<String> registered = new HashSet<>();
boolean safe = registered.add("my-metric-name"); // only call registerMetric if safe==true

Try / catch

try {
    context.registerMetric(name, metric, interval);
} catch (RuntimeException e) {
    if (e.getMessage().contains("registered twice")) {
        LOG.warn("metric {} already registered; reusing", name);
    } else { throw e; }
}

Prevention

When it happens

Trigger: Calling registerMetric twice with the same name string within the same task — e.g. registering "request-count" in both prepare and a helper method, or in a loop that re-registers on each execution.

Common situations: Copy-pasted metric registration code with duplicated names, metrics registered once per element/component in a loop when they should be registered once, re-preparing bolts with shared registration logic that isn't idempotent.

Understand the failure class

Background: "already exists" / EEXIST / FileAlreadyExistsException: what the 'file already exists' error means and how to fix it — this error's family across 37 libraries.

Related errors


AI-assisted analysis of nathanmarz/storm@cdb116e942 (2026-09-12). Data as JSON: /api/errors/9260ad2ea71344bd. Report an issue: GitHub.

Appendix: source

Thrown at storm-core/src/jvm/backtype/storm/task/TopologyContext.java:246

    public <T extends IMetric> T registerMetric(String name, T metric, int timeBucketSizeInSecs) {
        if((Boolean)_openOrPrepareWasCalled.deref() == true) {
            throw new RuntimeException("TopologyContext.registerMetric can only be called from within overridden " + 
                                       "IBolt::prepare() or ISpout::open() method.");
        }
        
        Map m1 = _registeredMetrics;
        if(!m1.containsKey(timeBucketSizeInSecs)) {
            m1.put(timeBucketSizeInSecs, new HashMap());
        }

        Map m2 = (Map)m1.get(timeBucketSizeInSecs);
        if(!m2.containsKey(_taskId)) {
            m2.put(_taskId, new HashMap());
        }

        Map m3 = (Map)m2.get(_taskId);
        if(m3.containsKey(name)) {
            throw new RuntimeException("The same metric name `" + name + "` was registered twice." );
        } else {
            m3.put(name, metric);
        }

        return metric;
    }

    /*
     * Convinience method for registering ReducedMetric.
     */
    public ReducedMetric registerMetric(String name, IReducer reducer, int timeBucketSizeInSecs) {
        return registerMetric(name, new ReducedMetric(reducer), timeBucketSizeInSecs);
    }
    /*
     * Convinience method for registering CombinedMetric.
     */
    public CombinedMetric registerMetric(String name, ICombiner combiner, int timeBucketSizeInSecs) {
        return registerMetric(name, new CombinedMetric(combiner), timeBucketSizeInSecs);

View on GitHub (pinned to cdb116e942)