microsoft/aspire · error

metric exporter

Error message

metric exporter: %w

What it means

setupOTel wraps the error from otlpmetricgrpc.New, which builds the gRPC OTLP metric exporter. Creation fails when the OTLP endpoint/URL is invalid or exporter options (TLS, headers, timeout) are inconsistent. The wrap "metric exporter: %w" preserves the root cause.

Solutions

  1. Check the metrics OTLP endpoint for a valid scheme and host:port and log the unwrapped error.
  2. Match the endpoint to the exporter type: use WithEndpoint(host:port) or WithEndpointURL(full url) consistently for the SDK version in use.
  3. Verify the collector/dashboard metrics port is open and reachable.
  4. Keep trace and metric exporters pointed at the same protocol (both grpc or both http).

Example fix

// before
metricExp, err := otlpmetricgrpc.New(ctx, metricOpts...)
if err != nil {
    return nil, fmt.Errorf("metric exporter: %w", err)
}
// after
if ep := os.Getenv("OTEL_EXPORTER_OTLP_ENDPOINT"); ep == "" {
    log.Println("OTEL_EXPORTER_OTLP_ENDPOINT not set; metrics disabled")
    return nil, nil
}
metricExp, err := otlpmetricgrpc.New(ctx, metricOpts...)
if err != nil {
    return nil, fmt.Errorf("metric exporter: %w", err)
}
Defensive patterns

Strategy: validation

Validate before calling

ep := os.Getenv("OTEL_EXPORTER_OTLP_ENDPOINT")
if u, err := url.Parse(ep); err != nil || u.Host == "" {
    return fmt.Errorf("invalid metrics OTLP endpoint %q", ep)
}

Try / catch

if err := setupOTel(...); err != nil {
    log.Printf("metrics exporter unavailable: %v", err) // degrade gracefully
}

Prevention

When it happens

Trigger: otlpmetricgrpc.New returns an error due to a malformed endpoint URL, invalid retry/timeout configuration, or bad TLS credentials, when setting up metrics via setupOTel.

Common situations: Wrong OTEL_EXPORTER_OTLP_ENDPOINT value, endpoint given as http://host:port while WithEndpoint expects host:port, misconfigured metrics collector address.

Understand the failure class

Background: "Invalid URL" errors: why new URL(), URI.parse, and reqwest::Url reject your string — missing scheme, whitespace, and bad path format — this error's family across 39 libraries.

Related errors


AI-assisted analysis of microsoft/aspire@25830f84bd (2026-09-16). Data as JSON: /api/errors/fe3e4b7ae124cd86. Report an issue: GitHub.

Appendix: source

Thrown at src/Aspire.Cli/Templating/Templates/go-starter/api/telemetry.go:70

		traceOpts = append(traceOpts, otlptracegrpc.WithHeaders(headers))
	}
	traceExp, err := otlptracegrpc.New(ctx, traceOpts...)
	if err != nil {
		return nil, fmt.Errorf("trace exporter: %w", err)
	}
	tp := sdktrace.NewTracerProvider(
		sdktrace.WithBatcher(traceExp),
		sdktrace.WithResource(res),
	)
	otel.SetTracerProvider(tp)

	metricOpts := []otlpmetricgrpc.Option{}
	if len(headers) > 0 {
		metricOpts = append(metricOpts, otlpmetricgrpc.WithHeaders(headers))
	}
	metricExp, err := otlpmetricgrpc.New(ctx, metricOpts...)
	if err != nil {
		return nil, fmt.Errorf("metric exporter: %w", err)
	}
	mp := sdkmetric.NewMeterProvider(
		sdkmetric.WithReader(sdkmetric.NewPeriodicReader(metricExp)),
		sdkmetric.WithResource(res),
	)
	otel.SetMeterProvider(mp)

	if err := runtime.Start(runtime.WithMeterProvider(mp)); err != nil {
		return nil, fmt.Errorf("runtime metrics: %w", err)
	}

	logOpts := []otlploggrpc.Option{}
	if len(headers) > 0 {
		logOpts = append(logOpts, otlploggrpc.WithHeaders(headers))
	}
	logExp, err := otlploggrpc.New(ctx, logOpts...)
	if err != nil {
		return nil, fmt.Errorf("log exporter: %w", err)

View on GitHub (pinned to 25830f84bd)