OpenTelemetry Error Guide: 'rpc error: code = Unimplemented' — Fix OTLP Endpoint & Protocol
Fix 'permanent error: rpc error: code = Unimplemented' when exporting OTLP: correct the endpoint, protocol, ports 4317/4318, and path so traces reach an OTLP-aware Collector.
- #opentelemetry
- #observability
- #troubleshooting
- #errors
Fixing errors like this? Get 500 free DevOps AI prompts
500 copy-paste AI prompts for the stack you actually run — one PDF, free.
Overview
This error appears when an OpenTelemetry exporter reaches a server over gRPC, but that server does not implement the OTLP trace/metric/log service. The Collector or SDK logs a permanent (non-retryable) failure:
2026-07-09T10:33:19.006Z error exporterhelper/common.go:296 Exporting failed. The error is not retryable. Dropping data. {"kind": "exporter", "data_type": "traces", "name": "otlp", "error": "Permanent error: rpc error: code = Unimplemented desc = unknown service opentelemetry.proto.collector.trace.v1.TraceService", "dropped_items": 256}
code = Unimplemented means the gRPC endpoint answered, but the OTLP TraceService (or MetricsService/LogsService) is not registered there — you are pointed at the wrong endpoint, wrong port, or a non-OTLP gRPC server.
Symptoms
- Every export fails identically and immediately; the error is marked non-retryable and data is dropped.
- The message names an
unknown service opentelemetry.proto.collector.trace.v1.TraceService. - The endpoint is reachable (no
connection refused), but rejects the OTLP method. - Often appears right after changing endpoints, ports, or switching gRPC vs HTTP.
- An HTTP/protobuf client hitting a gRPC-only port shows a related
404/Unimplemented-style rejection.
Common Root Causes
- Wrong port for the protocol — exporting gRPC OTLP to
4318(the HTTP port) or hitting a non-OTLP gRPC service. - Pointed at the wrong server — the endpoint is a load balancer, proxy, or app that speaks gRPC but not OTLP.
- Protocol mismatch — the SDK is configured for gRPC while only HTTP/protobuf is available (or vice-versa).
- Wrong HTTP path — HTTP/protobuf exports must POST to
/v1/traces,/v1/metrics, or/v1/logs. - Vendor endpoint expecting HTTP — some backends only accept OTLP/HTTP, not OTLP/gRPC.
- Collector missing the OTLP receiver — the target Collector never enabled
otlpfor that signal.
Diagnostic Workflow
Confirm the SDK’s protocol, endpoint, and (for HTTP) that the path matches the signal:
echo "$OTEL_EXPORTER_OTLP_PROTOCOL" # grpc | http/protobuf
echo "$OTEL_EXPORTER_OTLP_ENDPOINT" # grpc: host:4317 | http: host:4318
echo "$OTEL_EXPORTER_OTLP_TRACES_ENDPOINT" # http must end in /v1/traces
Ensure the target Collector actually registers the OTLP receiver for the signal you export, on the matching protocol:
receivers:
otlp:
protocols:
grpc:
endpoint: 0.0.0.0:4317
http:
endpoint: 0.0.0.0:4318
service:
pipelines:
traces:
receivers: [otlp]
processors: [batch]
exporters: [debug]
Probe the gRPC endpoint to see which services it exposes — the OTLP services must be listed:
grpcurl -plaintext otel-collector:4317 list
# expect: opentelemetry.proto.collector.trace.v1.TraceService
For HTTP/protobuf, confirm the exact path returns 200, not 404:
curl -v -X POST http://otel-collector:4318/v1/traces \
-H 'Content-Type: application/x-protobuf' --data-binary @/dev/null
Example Root Cause Analysis
A team switched their SDK to OTEL_EXPORTER_OTLP_PROTOCOL=grpc but kept OTEL_EXPORTER_OTLP_ENDPOINT=http://collector.example.com:4318. Port 4318 on their gateway ran the Collector’s HTTP receiver only; the gRPC exporter dialed it and the HTTP server had no OTLP gRPC TraceService, so every export returned code = Unimplemented. Because the error is permanent, the Collector dropped the data immediately with no retries.
The fix was to match the port to the protocol. For gRPC OTLP the endpoint became collector.example.com:4317, where the Collector’s otlp/grpc receiver was registered. A quick grpcurl -plaintext collector.example.com:4317 list then showed opentelemetry.proto.collector.trace.v1.TraceService, confirming the OTLP service was present, and exports succeeded on the next flush.
Prevention Best Practices
- Map protocol to port explicitly and consistently: gRPC OTLP on
4317, HTTP/protobuf OTLP on4318. - For HTTP/protobuf, always target the signal-specific path (
/v1/traces,/v1/metrics,/v1/logs). - Verify the target with
grpcurl ... listbefore rollout to confirm the OTLP services are registered. - Point exporters at an OTLP-aware Collector or a vendor’s documented OTLP endpoint — not a generic gRPC proxy.
- Treat
Unimplementedas a configuration bug, not a transient error; retries will never help. - Enable both protocols on gateway Collectors to tolerate clients configured either way.
Quick Command Reference
# SDK protocol/endpoint
env | grep OTEL_EXPORTER_OTLP
# List gRPC services exposed at the endpoint
grpcurl -plaintext otel-collector:4317 list
# Verify HTTP/protobuf path responds
curl -v -X POST http://otel-collector:4318/v1/traces \
-H 'Content-Type: application/x-protobuf' --data-binary @/dev/null
# Confirm the Collector enabled the otlp receiver
journalctl -u otelcol-contrib | grep -i 'otlp' | head
Conclusion
rpc error: code = Unimplemented is a routing problem, not a load or network problem: the server answered but does not speak OTLP for that signal. Align protocol and port (4317 gRPC, 4318 HTTP), use the correct HTTP path, and verify with grpcurl ... list that the OTLP TraceService is actually registered where you are pointing. Because the error is permanent, catching it at configuration time — not in production retries — is what keeps telemetry flowing.
Get 500 Battle-Tested DevOps AI Prompts — Free
500 battle-tested, copy-paste AI prompts engineered by a senior systems engineer — every one with fill-in placeholders and safety/back-out notes. Drop your email and it's yours.
- 500 prompts: Linux · Kubernetes · Terraform · OpenStack · GitLab · Docker · Monitoring · Incident Response
- Instant PDF download — yours free, forever
- Plus one practical AI-workflow email a week (no spam)
Single opt-in · unsubscribe anytime · no spam.