Skip to content

🐛 Bug Report: gRPC exporter fails with StatusCode.UNAVAILABLE when connecting to insecure OTLP collector #3480

@boscoraju-snyk

Description

@boscoraju-snyk

Which component is this bug for?

Traceloop SDK

📜 Description

When using the Traceloop SDK with a gRPC endpoint (no http:// prefix), the exporter fails with StatusCode.UNAVAILABLE even when:

  1. TCP connectivity to the endpoint works
  2. The OpenTelemetry Collector is configured to accept insecure gRPC connections

Root Cause

In traceloop/sdk/tracing/tracing.py, the init_spans_exporter function creates a GRPCExporter without setting insecure=True:

def init_spans_exporter(api_endpoint: str, headers: Dict[str, str]) -> SpanExporter:
    if "http" in api_endpoint.lower() or "https" in api_endpoint.lower():
        return HTTPExporter(endpoint=f"{api_endpoint}/v1/traces", headers=headers)
    else:
        return GRPCExporter(endpoint=f"{api_endpoint}", headers=headers)  # Missing insecure=True. The OpenTelemetry `OTLPSpanExporter` (gRPC) defaults `insecure=False`, which means it attempts a TLS connection. When the collector accepts insecure connections, the TLS handshake fails.

Environment

  • Traceloop SDK version: 0.49.1
  • Python version: 3.12
  • OpenTelemetry Collector configured with:
  receivers:
    otlp:
      protocols:
        grpc:
          endpoint: 0.0.0.0:4317  # No TLS configured

👟 Reproduction steps

  1. Configure Traceloop with a gRPC endpoint (no http/https prefix):
Traceloop.init(app_name="myapp",  api_endpoint="otelcol.example.com:4317")
  1. Run the application

  2. Observe error:

Failed to export traces to otelcol.example.com:4317, error code: StatusCode.UNAVAILABLE

👍 Expected behavior

The SDK should successfully connect to collectors that accept insecure gRPC connections.

👎 Actual Behavior with Screenshots

{"level": "error", "message": "Failed to export traces to otelcol.example.svc.cluster.local:4317, error code: StatusCode.UNAVAILABLE", "time": "2025-11-27T16:10:04.348Z", "caller": "/app/.venv/lib/python3.12/site-packages/opentelemetry/exporter/otlp/proto/grpc/exporter.py:416"}

{"level": "error", "message": "Failed to export traces to otelcol.example.svc.cluster.local:4317, error code: StatusCode.UNAVAILABLE", "time": "2025-11-27T16:10:06.299Z", "caller": "/app/.venv/lib/python3.12/site-packages/opentelemetry/exporter/otlp/proto/grpc/exporter.py:416"}

{"level": "warning", "message": "Transient error StatusCode.UNAVAILABLE encountered while exporting traces to otelcol.example.svc.cluster.local:4317, retrying in 0.80s.", "time": "2025-11-27T16:10:07.077Z", "caller": "/app/.venv/lib/python3.12/site-packages/opentelemetry/exporter/otlp/proto/grpc/exporter.py:424"}

🤖 Python Version

python3.12

📃 Provide any additional context for the Bug.

Support standard gRPC URL schemes like other gRPC clients:

Scheme Protocol TLS
grpc:// gRPC ❌ Insecure
grpcs:// gRPC ✅ Secure (TLS)
def init_spans_exporter(api_endpoint: str, headers: Dict[str, str]) -> SpanExporter:
    endpoint_lower = api_endpoint.lower()
    
    if endpoint_lower.startswith("http://") or endpoint_lower.startswith("https://"):
        return HTTPExporter(endpoint=f"{api_endpoint}/v1/traces", headers=headers)
    elif endpoint_lower.startswith("grpc://"):
        # Insecure gRPC
        clean_endpoint = api_endpoint[7:]  # Remove "grpc://"
        return GRPCExporter(endpoint=clean_endpoint, headers=headers, insecure=True)
    elif endpoint_lower.startswith("grpcs://"):
        # Secure gRPC (TLS)
        clean_endpoint = api_endpoint[8:]  # Remove "grpcs://"
        return GRPCExporter(endpoint=clean_endpoint, headers=headers, insecure=False)
    else:
        # No scheme: default to insecure gRPC for backward compatibility
        return GRPCExporter(endpoint=api_endpoint, headers=headers, insecure=True)

This follows the standard convention used by gRPC clients across languages:

  • grpc://host:port → insecure connection
  • grpcs://host:port → secure connection (TLS)

👀 Have you spent some time to check if this bug has been raised before?

  • I checked and didn't find similar issue

Are you willing to submit PR?

Yes I am willing to submit a PR!

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions