{"record":{"id":"1af571f4dddea394","repo":"pinpoint-apm/pinpoint","slug":"resource-attribute-service-name-is-required-to-s","errorCode":null,"errorMessage":"Resource attribute `service.name` is required to save OTLP metrics to Pinpoint.","messagePattern":"Resource attribute `service\\.name` 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":85,"sourceCode":"            logger.info(\"Failed saving OTLP metric {}: {}\", metric.getName(), ex.getMessage());\n            return null;\n        }\n\n        return builder.build();\n    }\n\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}","sourceCodeStart":67,"sourceCodeEnd":103,"githubUrl":"https://github.com/pinpoint-apm/pinpoint/blob/744c3d3075e595656abb1ae331ad2c0e4c9eb996/otlpmetric/otlpmetric-collector/src/main/java/com/navercorp/pinpoint/otlp/collector/mapper/OtlpMetricMapper.java#L67-L103","documentation":"The OTLP metric collector maps incoming OTLP metric data to Pinpoint's metric model. Every metric payload must carry a resource attribute `service.name`, which Pinpoint uses as the application/service identifier. parseCommonTags removes `service.name` from the merged resource+common tag map, and if it is absent or empty it aborts mapping with OtlpMappingException because a metric without a service name cannot be attributed to any Pinpoint application.","triggerScenarios":"An OTLP exporter (e.g. OpenTelemetry SDK, collector pipeline) sends metrics to Pinpoint's OTLP endpoint whose Resource attributes omit `service.name`, or set it to an empty string. Happens with Service.name/OTEL_RESOURCE_ATTRIBUTES not configured on the emitting side, or when a collector's metrics transform stage drops resource attributes.","commonSituations":"1) OTEL_SERVICE_NAME / OTEL_RESOURCE_ATTRIBUTES=service.name=... not set on the app emitting metrics. 2) OpenTelemetry Collector `resource` processor deleting the service.name attribute before forwarding to Pinpoint. 3) Custom SDK exporters that build Resource without ServiceResourceDetector.","solutions":["Set the `service.name` resource attribute on the OTLP exporter side (OTEL_SERVICE_NAME env var or ServiceResourceDetector in the SDK).","If routing through an OpenTelemetry Collector, keep/insert service.name in a `resource` processor (attributes: service.name: value) before exporting to Pinpoint.","If your agent wraps Pinpoint telemetry, ensure pinpoint.applicationName is mapped to `service.name` in the resource.","Wrap the OTLP submission in a try/catch for OtlpMappingException on the producer side and log/reject the payload with a clear client-side message."],"exampleFix":"// before (client side)\nSdkMeterProvider.builder().setResource(Resource.empty())\n// after\nSdkMeterProvider.builder().setResource(Resource.getDefault().merge(Resource.builder().put(\"service.name\", \"my-app\").build()))","handlingStrategy":"validation","validationCode":"// client-side, before exporting OTLP metrics\nResource res = Resource.getDefault();\nString serviceName = res.getAttributes().get(AttributeKey.stringKey(\"service.name\"));\nif (serviceName == null || serviceName.isEmpty()) {\n    throw new IllegalStateException(\"OTLP export to Pinpoint requires resource attribute `service.name`\");\n}","typeGuard":"boolean hasServiceName(io.opentelemetry.api.common.Attributes attrs) {\n    String v = attrs.get(AttributeKey.stringKey(\"service.name\"));\n    return v != null && !v.isEmpty();\n}","tryCatchPattern":"try {\n    otlpGrpcMetricExporter.export(metrics);\n} catch (OtlpMappingException | io.opentelemetry.sdk.metrics.internal.export.SdkMeterProviderException e) {\n    log.error(\"Pinpoint rejected OTLP metrics: {}\", e.getMessage());\n}","preventionTips":["Always set OTEL_SERVICE_NAME (or SDK ServiceResourceDetector) in every service emitting to Pinpoint.","Audit OpenTelemetry Collector pipelines for resource processors that drop service.name.","Add a startup check that logs the resolved Resource attributes.","Smoke-test metric export to Pinpoint right after deploy."],"tags":["java","otlp","opentelemetry","pinpoint","metrics","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"}