redis/go-redis · error
redisotel: %T not supported
Error message
redisotel: %T not supported
What it means
redisotel.InstrumentMetrics only supports *redis.Client, *redis.ClusterClient, and *redis.Ring. When a UniversalClient holds a concrete type outside this set (e.g. a custom implementation, a failover client reached through an interface wrapper, or a nil client), the default case returns '%T not supported'. Note the failover client (*redis.FailoverClient via redis.NewFailoverClient) is NOT in the switch, so it hits this error.
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 c5cad058c7)
Solutions
- Use a supported client type: Client, ClusterClient, or Ring
- For sentinel failover, instrument via a wrapper or check for newer redisotel versions that add FailoverClient support
- Ensure the variable's concrete type is one of the supported types (e.g. not a generic interface parameter)
- Instrument each underlying *redis.Client directly if you manage failover manually
Example fix
// before
rdb := redis.NewFailoverClient(failoverOpt)
redisotel.InstrumentMetrics(rdb) // panics into: redisotel: *redis.FailoverClient not supported
// after
rdb := redis.NewClient(&redis.Options{Addr: "localhost:6379"})
redisotel.InstrumentMetrics(rdb) Defensive patterns
Strategy: type-guard
Type guard
func instrumentable(rdb redis.UniversalClient) bool {
switch rdb.(type) {
case *redis.Client, *redis.ClusterClient, *redis.Ring:
return rdb != nil
default:
return false
}
} Try / catch
if err := redisotel.InstrumentMetrics(rdb); err != nil {
if strings.Contains(err.Error(), "not supported") {
log.Printf("metrics unsupported for %T", rdb)
}
} Prevention
- Only call redisotel on Client/ClusterClient/Ring
- For sentinel, instrument underlying per-node clients or upgrade redisotel
- Avoid storing clients in a lossy UniversalClient variable when instrumenting
When it happens
Trigger: Calling InstrumentMetrics with a client whose dynamic type is not *redis.Client, *redis.ClusterClient, or *redis.Ring — most commonly a Sentinel failover client or a stub/mock UniversalClient, or passing a nil client.
Common situations: Using redis.NewFailoverClient (sentinel) with redisotel metrics; wrapping clients in a custom struct that implements UniversalClient; tests injecting mocks.
Related errors
- redisotel: %T not supported
- 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 redis/go-redis@c5cad058c7 (2026-09-01).
Data as JSON: /api/errors/d26876eb1d7bdf12.
Report an issue: GitHub.