Skip to content
Latchkey

OpenTelemetry Go "traces export: connection refused" (otlptrace) in CI

The Go otlptrace exporter dials a collector at localhost:4317 (gRPC) or 4318 (HTTP). In CI nothing listens there, so exports fail with connection refused, and TracerProvider.Shutdown may return the same error.

What this error means

Test output logs "traces export: Post ... dial tcp 127.0.0.1:4318: connect: connection refused" or the gRPC equivalent, and tp.Shutdown(ctx) returns a non-nil error the test does not handle.

text
traces export: Post "http://localhost:4318/v1/traces": dial tcp
127.0.0.1:4318: connect: connection refused

Common causes

No collector on the OTLP port in CI

The exporter targets the default local OTLP endpoint. With no collector service, every gRPC/HTTP dial is refused.

Shutdown surfaces the export error

TracerProvider.Shutdown flushes pending spans; when the endpoint is dead it returns the connection error, which can fail a test that asserts err == nil.

How to fix it

Use a no-op or in-memory exporter in tests

  1. For unit tests, use tracetest.NewInMemoryExporter() and assert on its spans.
  2. For code that only needs a provider, use a provider without a network exporter.
  3. Do not fail the test on Shutdown when no collector is expected.
main_test.go
import "go.opentelemetry.io/otel/sdk/trace/tracetest"

exp := tracetest.NewInMemoryExporter()
tp := trace.NewTracerProvider(trace.WithSyncer(exp))
// exp.GetSpans() for assertions

Run a collector service if export is under test

Start a collector and set the endpoint env var when the test genuinely needs a live export.

.github/workflows/ci.yml
env:
  OTEL_EXPORTER_OTLP_ENDPOINT: http://otelcol:4317

How to prevent it

  • Use tracetest.InMemoryExporter for span assertions.
  • Do not point tests at a live collector unless one runs in the job.
  • Handle Shutdown errors instead of asserting they are always nil.

Related guides

Tired of flaky CI? Latchkey auto-heals failed jobs and retries them for you. Start free →