go-redis/redis · error
redisotel: %T not supported
Error message
redisotel: %T not supported
What it means
Returned by InstrumentMetrics (extra/redisotel/metrics.go:55) when the passed redis.UniversalClient is not one of the supported concrete types (*redis.Client, *redis.ClusterClient, *redis.Ring) and no explicit poolName was configured. The type switch falls through to the default case because the client wrapper type is unrecognized.
Source
Thrown at extra/redisotel/metrics.go:55
metric.WithInstrumentationVersion("semver:"+redis.Version()),
)
}
if conf.poolName == "" {
switch rdb := rdb.(type) {
case *redis.Client:
conf.poolName = rdb.Options().Addr
case *redis.ClusterClient:
for _, addr := range rdb.Options().Addrs {
conf.poolName = addr
break
}
case *redis.Ring:
for _, addr := range rdb.Options().Addrs {
conf.poolName = addr
break
}
default:
return fmt.Errorf("redisotel: %T not supported", rdb)
}
}
conf.attrs = append(conf.attrs, attribute.String("pool.name", conf.poolName))
var state *metricsState
if conf.closeChan != nil {
state = &metricsState{
registrations: make([]metric.Registration, 0),
closed: false,
mutex: sync.Mutex{},
}
go func() {
<-conf.closeChan
state.mutex.Lock()
state.closed = true
View on GitHub (pinned to 36d97525cd)
Solutions
- Pass the concrete *redis.Client, *redis.ClusterClient, or *redis.Ring directly to InstrumentMetrics
- Use the WithPoolName option to pre-set conf.poolName so the type switch is skipped entirely
- If using a UniversalClient wrapper, unwrap it to the underlying concrete client before passing it to InstrumentMetrics
Example fix
// before - passing a UniversalClient wrapper
var rdb redis.UniversalClient = getUniversalClient()
err := redisotel.InstrumentMetrics(rdb)
// returns: redisotel: *universalClient not supported
// after - pass the concrete type, or set poolName explicitly
err := redisotel.InstrumentMetrics(rdb.(*redis.Client))
// or:
err := redisotel.InstrumentMetrics(rdb, redisotel.WithPoolName("my-pool")) Defensive patterns
Strategy: type-guard
Type guard
// Check the concrete client type before calling InstrumentMetrics
switch rdb.(type) {
case *redis.Client, *redis.ClusterClient, *redis.Ring:
// supported - proceed
default:
log.Fatalf("redisotel.InstrumentMetrics does not support client type %T; unwrap or set poolName", rdb)
} Try / catch
if err := redisotel.InstrumentMetrics(rdb, redisotel.WithPoolName("my-pool")); err != nil {
if strings.Contains(err.Error(), "not supported") {
log.Errorf("unsupported client type %T; pass *redis.Client/*ClusterClient/*Ring or set poolName", rdb)
}
} Prevention
- Pass concrete client types (*redis.Client, *redis.ClusterClient, *redis.Ring) to InstrumentMetrics, not wrappers
- Use the WithPoolName option to bypass the type switch when passing custom client types
- Unwrap UniversalClient to its underlying concrete client before instrumentation
When it happens
Trigger: Calling redisotel.InstrumentMetrics with a client type other than *redis.Client, *redis.ClusterClient, or *redis.Ring without setting the WithMetricsDestinationAddr/WithPoolName option to pre-populate conf.poolName.
Common situations: Passing a redis.UniversalClient that wraps one of the supported types but is itself a different concrete type; using a custom client implementation that satisfies the UniversalClient interface but is not one of the three built-in types; wrapping the client in a decorator or mock.
Related errors
- redisotel: already initialized, call Shutdown() before reini
- failed to create metrics recorder: %w
- failed to create operation duration histogram: %w
- failed to create connection count metric: %w
- failed to create connection create time histogram: %w
AI-assisted analysis of go-redis/redis@36d97525cd (2026-08-06).
Data as JSON: /data/errors/7817f16dee546005.json.
Report an issue: GitHub.