{"record":{"id":"57f03a59b448f25d","repo":"pinpoint-apm/pinpoint","slug":"resource-attribute-pinpoint-agentid-is-required","errorCode":null,"errorMessage":"Resource attribute `pinpoint.agentId` is required to save OTLP metrics to Pinpoint","messagePattern":"Resource attribute `pinpoint\\.agentId` is required to save OTLP metrics to Pinpoint","errorType":"validation","errorClass":"OtlpMappingException","httpStatus":null,"severity":"error","filePath":"otlpmetric/otlpmetric-collector/src/main/java/com/navercorp/pinpoint/otlp/collector/mapper/OtlpMetricMapper.java","lineNumber":91,"sourceCode":"\n    private void map(OtlpMetricData.Builder builder, Metric metric, Map<String, String> commonTags) {\n        for (OtlpMetricDataMapper mapper : mappers) {\n            mapper.map(builder, metric, commonTags);\n        }\n    }\n\n    private Map<String, String> parseCommonTags(OtlpMetricData.Builder builder, Map<String, String> tags) {\n        Map<String, String> commonTags = new HashMap<>(tags);\n\n        String serviceName = commonTags.remove(OtlpResourceAttributes.KEY_SERVICE_NAME);\n        if (StringUtils.isEmpty(serviceName)) {\n            throw new OtlpMappingException(\"Resource attribute `service.name` is required to save OTLP metrics to Pinpoint.\");\n        }\n        builder.setServiceName(serviceName);\n\n        String agentId = commonTags.remove(OtlpResourceAttributes.KEY_PINPOINT_AGENTID);\n        if (StringUtils.isEmpty(serviceName)) {\n            throw new OtlpMappingException(\"Resource attribute `pinpoint.agentId` is required to save OTLP metrics to Pinpoint\");\n        }\n\n        builder.setAgentId(agentId);\n\n        String version = commonTags.remove(OtlpResourceAttributes.KEY_PINPOINT_METRIC_VERSION);\n        if (StringUtils.isEmpty(version) == false) {\n            builder.setVersion(version);\n        }\n\n        return commonTags;\n    }\n}\n","sourceCodeStart":73,"sourceCodeEnd":104,"githubUrl":"https://github.com/pinpoint-apm/pinpoint/blob/744c3d3075e595656abb1ae331ad2c0e4c9eb996/otlpmetric/otlpmetric-collector/src/main/java/com/navercorp/pinpoint/otlp/collector/mapper/OtlpMetricMapper.java#L73-L104","documentation":"parseCommonTags requires the resource attribute `pinpoint.agentId` (in addition to `service.name`) so metrics can be attributed to a specific agent in Pinpoint. When it is missing or empty, OtlpMappingException is thrown. Note the guard has a copy-paste bug: it re-checks `serviceName` instead of `agentId`, so this error only fires when service.name was also empty (or never when only agentId is empty) — a null/empty agentId silently flows into builder.setAgentId.","triggerScenarios":"An OTLP metrics payload whose Resource lacks the `pinpoint.agentId` attribute (OtlpResourceAttributes.KEY_PINPOINT_AGENTID) reaches parseCommonTags and service.name is also empty; or the attribute exists but is blank while the faulty serviceName check still evaluates true.","commonSituations":"1) Emitting via a stock OpenTelemetry SDK which knows nothing about Pinpoint's custom `pinpoint.agentId` attribute. 2) A Collector `resource` processor that strips non-standard attributes. 3) Version change in the Pinpoint OTLP contract where the attribute key was renamed.","solutions":["Add the `pinpoint.agentId` resource attribute on the exporter (Resource.builder().put(\"pinpoint.agentId\", agentId)).","Fix the mapper bug so the guard checks the right variable: `if (StringUtils.isEmpty(agentId)) throw ...` (see exampleFix).","If routing through a Collector, use a `resource` processor to inject pinpoint.agentId before export.","Verify the exact attribute key matches OtlpResourceAttributes.KEY_PINPOINT_AGENTID for your Pinpoint version (naming drift across versions)."],"exampleFix":"// before (OtlpMetricMapper.java)\nString agentId = commonTags.remove(OtlpResourceAttributes.KEY_PINPOINT_AGENTID);\nif (StringUtils.isEmpty(serviceName)) {\n    throw new OtlpMappingException(\"Resource attribute `pinpoint.agentId` is required to save OTLP metrics to Pinpoint\");\n}\n// after\nString agentId = commonTags.remove(OtlpResourceAttributes.KEY_PINPOINT_AGENTID);\nif (StringUtils.isEmpty(agentId)) {\n    throw new OtlpMappingException(\"Resource attribute `pinpoint.agentId` is required to save OTLP metrics to Pinpoint\");\n}","handlingStrategy":"validation","validationCode":"Resource res = Resource.getDefault();\nString agentId = res.getAttributes().get(AttributeKey.stringKey(\"pinpoint.agentId\"));\nString serviceName = res.getAttributes().get(AttributeKey.stringKey(\"service.name\"));\nif (isBlank(serviceName) || isBlank(agentId)) {\n    throw new IllegalStateException(\"Pinpoint OTLP export requires `service.name` and `pinpoint.agentId` resource attributes\");\n}","typeGuard":"boolean hasAgentId(io.opentelemetry.api.common.Attributes attrs) {\n    String v = attrs.get(AttributeKey.stringKey(\"pinpoint.agentId\"));\n    return v != null && !v.isEmpty();\n}","tryCatchPattern":"try {\n    exporter.export(metrics);\n} catch (OtlpMappingException e) {\n    log.error(\"Missing Pinpoint resource attribute: {}\", e.getMessage());\n}","preventionTips":["Set pinpoint.agentId alongside service.name in the Resource on every exporter.","Keep the attribute key in a shared constant and verify it matches OtlpResourceAttributes.KEY_PINPOINT_AGENTID for your Pinpoint version.","When upgrading Pinpoint, diff the OtlpResourceAttributes key set and update exporters.","Review mapper guards for copy-paste mistakes (this one checked serviceName instead of agentId)."],"tags":["java","otlp","pinpoint","copy-paste-bug","validation"],"backgroundTag":"missing-required-config-field","analyzedSha":"744c3d3075e595656abb1ae331ad2c0e4c9eb996","analyzedAt":"2026-09-07T18:48:45.289Z","contentChangedAt":"2026-09-07T18:48:45.289Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}