{"id":"ccd94649cf1baf2e","repo":"apache/kafka","slug":"cannot-use-tagname-as-a-tag-name","errorCode":null,"errorMessage":"Cannot use {tagName} as a tag name","messagePattern":"Cannot use (.+?) as a tag name","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"clients/src/main/java/org/apache/kafka/common/metrics/internals/PluginMetricsImpl.java","lineNumber":52,"sourceCode":"    private static final String GROUP = \"plugins\";\n\n    private final Metrics metrics;\n    private final Map<String, String> tags;\n    private final Set<MetricName> metricNames = ConcurrentHashMap.newKeySet();\n    private final Set<String> sensors = ConcurrentHashMap.newKeySet();\n    private volatile boolean closing = false;\n\n    public PluginMetricsImpl(Metrics metrics, Map<String, String> tags) {\n        this.metrics = metrics;\n        this.tags = tags;\n    }\n\n    @Override\n    public MetricName metricName(String name, String description, LinkedHashMap<String, String> tags) {\n        if (closing) throw new IllegalStateException(\"This PluginMetrics instance is closed\");\n        for (String tagName : tags.keySet()) {\n            if (this.tags.containsKey(tagName)) {\n                throw new IllegalArgumentException(\"Cannot use \" + tagName + \" as a tag name\");\n            }\n        }\n        Map<String, String> metricsTags = new LinkedHashMap<>(this.tags);\n        metricsTags.putAll(tags);\n        return metrics.metricName(name, GROUP, description, metricsTags);\n    }\n\n    @Override\n    public void addMetric(MetricName metricName, MetricValueProvider<?> metricValueProvider) {\n        if (closing) throw new IllegalStateException(\"This PluginMetrics instance is closed\");\n        if (metricNames.contains(metricName)) {\n            throw new IllegalArgumentException(\"Metric \" + metricName + \" already exists\");\n        }\n        metrics.addMetric(metricName, metricValueProvider);\n        metricNames.add(metricName);\n    }\n\n    @Override","sourceCodeStart":34,"sourceCodeEnd":70,"githubUrl":"https://github.com/apache/kafka/blob/c31c9215e131f8c17e79f8901b48c13ee6aa8e7a/clients/src/main/java/org/apache/kafka/common/metrics/internals/PluginMetricsImpl.java#L34-L70","documentation":"Thrown by PluginMetricsImpl.metricName when one of the caller-supplied tag keys is already present in the instance's reserved tag map (this.tags). PluginMetricsImpl prepends a fixed set of tags (group \"plugins\" plus plugin-identifying tags) to every metric name; allowing a plugin to overwrite them would corrupt the namespace and break metric identity. The collision is rejected with IllegalArgumentException naming the offending tag.","triggerScenarios":"Calling pluginMetrics.metricName(name, description, tags) where tags.keySet() intersects this.tags (the reserved tags assigned at PluginMetricsImpl construction, e.g. plugin-name / plugin-id). Any duplicate key triggers the exception before the maps are merged.","commonSituations":"A plugin that adds a generic tag like \"plugin\" or \"client-id\" that the framework already injects; refactors that change which tags the framework reserves without updating plugins; a plugin reused across framework versions where the reserved-tag set differs.","solutions":["Inspect PluginMetricsImpl's reserved tags for your framework version and remove any of those keys from your plugin's tag map.","Prefix plugin-specific tag names (e.g. \"my-plugin-stage\") so they cannot collide with reserved framework tags.","Log tags.keySet() vs the reserved set when the exception fires to identify the exact overlapping key.","Update the plugin to the framework's current reserved-tag contract (check the PluginMetrics instance tags at construction)."],"exampleFix":"// before\nLinkedHashMap<String,String> tags = new LinkedHashMap<>();\ntags.put(\"plugin-name\", \"my-plugin\"); // reserved by framework\nMetricName n = pluginMetrics.metricName(\"rx\", \"desc\", tags); // throws\n\n// after\nLinkedHashMap<String,String> tags = new LinkedHashMap<>();\ntags.put(\"stage\", \"fetch\"); // non-reserved key\nMetricName n = pluginMetrics.metricName(\"rx\", \"desc\", tags);","handlingStrategy":"validation","validationCode":"// reservedTagNames = the identity tags owned by the PluginMetrics instance (e.g. client/connector id).\n// Strip or rename any caller-supplied tag that collides with them.\nSet<String> reservedTagNames = Set.of(/* framework identity tag keys */);\nLinkedHashMap<String, String> safeTags = new LinkedHashMap<>();\nfor (Map.Entry<String, String> e : callerTags.entrySet()) {\n    if (!reservedTagNames.contains(e.getKey())) {\n        safeTags.put(e.getKey(), e.getValue());\n    }\n}\npluginMetrics.metricName(name, description, safeTags);","typeGuard":"static boolean hasNoReservedTags(LinkedHashMap<String, String> tags, Set<String> reserved) {\n    for (String k : tags.keySet()) if (reserved.contains(k)) return false;\n    return true;\n}","tryCatchPattern":null,"preventionTips":["Never reuse framework identity tags (e.g. client-id / connector-name) as your own metric tags.","Prefix custom tag names with a plugin-specific namespace to avoid collisions.","If unsure which tags are reserved, catch IllegalArgumentException once to discover them, then add them to a blocklist."],"tags":["metrics","plugin","tags","namespace-collision"],"analyzedSha":"c31c9215e131f8c17e79f8901b48c13ee6aa8e7a","analyzedAt":"2026-08-03T12:34:05.770Z","schemaVersion":2}