pinpoint-apm/pinpoint · error · RuntimeException

AnnotationKey code of

Error message

AnnotationKey code of ${pair} is duplicated with ${prev}

What it means

TraceMetadataLoader.check registers AnnotationKeys into a code->pair map while loading TraceMetadataProviders. If two providers declare AnnotationKeys with the same integer code, the second put returns the previous entry and this RuntimeException is thrown, aborting metadata loading. It is a deliberate duplicate-registration guard so annotation codes stay unambiguous across providers.

Solutions

  1. Find the two AnnotationKey definitions named in the message and change your custom key's code to an unused value (use AnnotationKeyFactory / pick a code outside Pinpoint's reserved ranges, e.g. a high vendor range).
  2. Check the classpath for duplicate plugin jars or stale old versions of your provider and remove them.
  3. Verify all TraceMetadataProviders registered via ServiceLoader are intentional; remove test/development providers from the deployment.

Example fix

// before
public static final AnnotationKey MY_KEY = AnnotationKeyFactory.of(1200, "MY_KEY");
// after
public static final AnnotationKey MY_KEY = AnnotationKeyFactory.of(9500, "MY_KEY"); // unused code
Defensive patterns

Strategy: validation

Validate before calling

// before loading, ensure unique codes across providers
Map<Integer, String> seen = new HashMap<>();
for (AnnotationKey key : myProvider.getAnnotationKeys()) {
    String prev = seen.putIfAbsent(key.getCode(), key.getName());
    if (prev != null) throw new IllegalStateException("Duplicate AnnotationKey code " + key.getCode());
    seen.put(key.getCode(), key.getName());
}

Try / catch

try {
    loader.load(provider);
} catch (RuntimeException e) {
    if (e.getMessage() != null && e.getMessage().contains("is duplicated with")) {
        logger.error("Duplicate AnnotationKey code in provider", e); // fail fast, fix codes
    } else { throw e; }
}

Prevention

When it happens

Trigger: Calling TraceMetadataLoader.load (via ServiceTypeRegistry/AnnotationKeyRegistry building) when two loaded TraceMetadataProvider implementations both return AnnotationKey objects with the same getCode() value from their addAnnotationKeys/addAllAnnotationKeys callbacks.

Common situations: A plugin bundle and a custom provider both define AnnotationKey with a hand-picked code that collides with Pinpoint's built-in codes (e.g. reusing code 1/10/9000); two versions of a plugin jar on the classpath each registering the same keys; copy-pasting an AnnotationKey definition and forgetting to change the code.

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 pinpoint-apm/pinpoint@744c3d3075 (2026-09-07). Data as JSON: /api/errors/69da206eec32745d. Report an issue: GitHub.

Appendix: source

Thrown at commons-profiler/src/main/java/com/navercorp/pinpoint/common/profiler/trace/TraceMetadataLoader.java:260

                logger.info(serviceTypePairToString(serviceType));
            }
        }

        private int getCode(Pair<ServiceType> p) {
            return p.value.getCode();
        }
    }

    private class AnnotationKeyChecker {
        private final Map<Integer, Pair<AnnotationKey>> annotationKeyCodeMap = new HashMap<>();

        private void check(AnnotationKey key, TraceMetadataProvider provider) {
            Pair<AnnotationKey> pair = new Pair<>(key, provider);
            Pair<AnnotationKey> prev = annotationKeyCodeMap.put(key.getCode(), pair);
    
            if (prev != null) {
                // TODO change exception type
                throw new RuntimeException("AnnotationKey code of " + annotationKeyPairToString(pair) + " is duplicated with " + annotationKeyPairToString(prev));
            }
        }

        private void logResult() {
            logger.info("Finished loading AnnotationKeys:");

            List<Pair<AnnotationKey>> annotationKeys = new ArrayList<>(annotationKeyCodeMap.values());
            annotationKeys.sort(Comparator.comparingInt(this::getCode));

            for (Pair<AnnotationKey> annotationKey : annotationKeys) {
                logger.info(annotationKeyPairToString(annotationKey));
            }
        }

        private int getCode(Pair<AnnotationKey> a) {
            return a.value.getCode();
        }
    }

View on GitHub (pinned to 744c3d3075)