redis/go-redis · error

failed to create connection relaxed timeout metric: %w

Error message

failed to create connection relaxed timeout metric: %w

What it means

Returned by createRecorder when meter.Int64UpDownCounter fails to create the redis.client.connection.relaxed_timeout UpDownCounter, a go-redis-specific gauge tracking timeout relaxations after server maintenance notifications. Init aborts, so connection-basic metrics are not installed. Root cause is again a failing MeterProvider.

Source

Thrown at extra/redisotel-native/redisotel.go:233

		if cfg.histAggregation == HistogramAggregationExplicitBucket {
			connectionCreateTimeOpts = append(connectionCreateTimeOpts,
				metric.WithExplicitBucketBoundaries(cfg.bucketsConnectionCreateTime...),
			)
		}
		var connectionCreateTimeConv dbconv.ClientConnectionCreateTime
		connectionCreateTimeConv, err = dbconv.NewClientConnectionCreateTime(meter, connectionCreateTimeOpts...)
		if err != nil {
			return nil, fmt.Errorf("failed to create connection create time histogram: %w", err)
		}
		connectionCreateTime = connectionCreateTimeConv.Inst()

		connectionRelaxedTimeout, err = meter.Int64UpDownCounter(
			MetricConnectionRelaxedTimeout,
			metric.WithDescription("How many times the connection timeout has been increased/decreased (after a server maintenance notification)"),
			metric.WithUnit("{relaxation}"),
		)
		if err != nil {
			return nil, fmt.Errorf("failed to create connection relaxed timeout metric: %w", err)
		}

		connectionHandoff, err = meter.Int64Counter(
			MetricConnectionHandoff,
			metric.WithDescription("Connections that have been handed off to another node (e.g after a MOVING notification)"),
		)
		if err != nil {
			return nil, fmt.Errorf("failed to create connection handoff metric: %w", err)
		}
	}

	var clientErrors metric.Int64Counter
	var maintenanceNotifications metric.Int64Counter

	if cfg.isMetricGroupEnabled(MetricGroupResiliency) {
		clientErrors, err = meter.Int64Counter(
			MetricClientErrors,
			metric.WithDescription("Number of errors handled by the Redis client"),

View on GitHub (pinned to c5cad058c7)

Solutions

  1. Call Shutdown() on the ObservabilityInstance before re-running Init (Init errors with 'already initialized' otherwise, but provider conflicts can surface here too)
  2. Ensure only one library registers the redis.client.connection.relaxed_timeout instrument name
  3. Provide a healthy MeterProvider via cfg.MeterProvider and keep it alive for the process lifetime
  4. Unwrap the error for the SDK-level reason and fix the provider configuration
  5. Disable MetricGroupFlagConnectionBasic if these maintenance-notification metrics are not needed

Example fix

// before
_ = obs.Init(cfg) // provider already Shutdown() earlier
// after
if err := obs.Shutdown(); err != nil { /* log */ }
provider = sdkmetric.NewMeterProvider(sdkmetric.WithReader(reader))
if err := obs.Init(&redisotel.Config{Enabled: true, MeterProvider: provider}); err != nil { /* log */ }
Defensive patterns

Strategy: try-catch

Validate before calling

if cfg.MetricGroups&redisotel.MetricGroupFlagConnectionBasic != 0 && !obsEnabledFreshly {
    // ensure obs.Shutdown() was called before re-Init
}

Try / catch

if err := obs.Init(cfg); err != nil {
    otel.Handle(err)
    // degrade: continue running without relaxed-timeout metrics
}

Prevention

When it happens

Trigger: Init with MetricGroupFlagConnectionBasic enabled against a shut-down, misconfigured, or instrument-rejecting MeterProvider; conflicting prior registration of an instrument with the same name but different unit/description in some strict providers.

Common situations: Re-initializing observability after Shutdown in long-running services; registering the same metric name through two different libraries with conflicting attributes; test harnesses replacing the global provider mid-run.

Understand the failure class

Related errors


AI-assisted analysis of redis/go-redis@c5cad058c7 (2026-09-01). Data as JSON: /api/errors/627e71f5f7c435e8. Report an issue: GitHub.