caddyserver/caddy · error

building OTLP metrics resource: %w

Error message

building OTLP metrics resource: %w

What it means

After creating the metric reader, Caddy merges resource.Default() with a schemaless resource carrying WebEngineName/WebEngineVersion via resource.Merge. Per OTel semantics, merging resources whose schema URLs conflict returns an error, which is wrapped as 'building OTLP metrics resource'. The error path also exists because NewSchemaless construction itself can fail (invalid attribute values).

Source

Thrown at modules/caddyhttp/metrics.go:202

	// NewMetricReader. It is NOT a MetricOption and must not be passed as one.
	// Users can still override the source by setting OTEL_METRICS_PRODUCERS.
	reg := ctx.GetMetricsRegistry()
	autoexport.WithFallbackMetricProducer(func(context.Context) (sdkmetric.Producer, error) {
		return otelprom.NewMetricProducer(otelprom.WithGatherer(reg)), nil
	})

	reader, err := autoexport.NewMetricReader(ctx)
	if err != nil {
		return fmt.Errorf("creating OTLP metric reader: %w", err)
	}

	version, _ := caddy.Version()
	res, err := resource.Merge(resource.Default(), resource.NewSchemaless(
		semconv.WebEngineName(ServerHeader),
		semconv.WebEngineVersion(version),
	))
	if err != nil {
		return fmt.Errorf("building OTLP metrics resource: %w", err)
	}

	m.meterProvider = sdkmetric.NewMeterProvider(
		sdkmetric.WithResource(res),
		sdkmetric.WithReader(reader),
	)

	return nil
}

// shutdown flushes and tears down the OTLP MeterProvider if one was provisioned.
// Both ForceFlush and Shutdown are always attempted so that a flush failure
// does not prevent the reader goroutines from being stopped; errors from both
// are returned joined.
func (m *Metrics) shutdown(ctx context.Context) error {
	if m == nil || m.meterProvider == nil {
		return nil
	}

View on GitHub (pinned to 50e54ee279)

Solutions

  1. Sanitize OTEL_RESOURCE_ATTRIBUTES: comma-separated key=value pairs with valid keys/values; remove stray quotes/semicolons.
  2. Simplify detection: temporarily unset OTEL_RESOURCE_ATTRIBUTES and OTEL_SERVICE_NAME to isolate the conflict.
  3. Align otel library versions (go.mod tidy/upgrade) to a consistent release line.
  4. If unneeded, disable the OTLP metrics block and rely on the local Prometheus endpoint exposed by `metrics`.

Example fix

# before
export OTEL_RESOURCE_ATTRIBUTES="service.name=caddy;bad-entry"

# after
export OTEL_RESOURCE_ATTRIBUTES="service.name=caddy"
Defensive patterns

Strategy: validation

Validate before calling

# Shell: keep OTEL_RESOURCE_ATTRIBUTES well-formed key=value pairs
export OTEL_RESOURCE_ATTRIBUTES="service.name=caddy,service.namespace=edge"
# avoid semicolons, stray quotes, empty keys

Prevention

When it happens

Trigger: resource.Merge conflict is possible when default resource detection yields attributes with a schema URL that conflicts with the schemaless addition — rare, but can happen with OTEL_RESOURCE_ATTRIBUTES or OTEL_SERVICE_NAME producing conflicting-detection results; more practically, malformed OTEL_RESOURCE_ATTRIBUTES values (bad key/value pairs) poison resource.Default().

Common situations: Containers where multiple resource detectors (env, host, cloud) produce inconsistent schema URLs; hand-written OTEL_RESOURCE_ATTRIBUTES with syntax errors; OTel library version combinations with known merge-conflict bugs.

Related errors


AI-assisted analysis of caddyserver/caddy@50e54ee279 (2026-08-15). Data as JSON: /api/errors/de2377e856766494. Report an issue: GitHub.