{"id":"eb7272f4c2d65877","repo":"go-redis/redis","slug":"redisotel-already-initialized-call-shutdown-be","errorCode":null,"errorMessage":"redisotel: already initialized, call Shutdown() before reinitializing","messagePattern":"redisotel: already initialized, call Shutdown\\(\\) before reinitializing","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"extra/redisotel-native/redisotel.go","lineNumber":77,"sourceCode":"// GetObservabilityInstance returns the global observability singleton.\nfunc GetObservabilityInstance() *ObservabilityInstance {\n\tobservabilityInstanceOnce.Do(func() {\n\t\tobservabilityInstance = &ObservabilityInstance{}\n\t})\n\treturn observabilityInstance\n}\n\n// Init initializes OpenTelemetry observability globally for all Redis clients.\n// This should be called once at application startup, BEFORE creating any Redis clients.\n// After initialization, all Redis clients will automatically collect and export\n// metrics without needing any additional configuration.\nfunc (o *ObservabilityInstance) Init(cfg *Config) error {\n\to.mu.Lock()\n\tdefer o.mu.Unlock()\n\n\t// If already initialized, return error\n\tif o.initialized {\n\t\treturn errors.New(\"redisotel: already initialized, call Shutdown() before reinitializing\")\n\t}\n\n\to.config = cfg\n\n\tif !cfg.Enabled {\n\t\treturn nil\n\t}\n\n\t// Get meter provider (use global if not provided)\n\tmeterProvider := cfg.MeterProvider\n\tif meterProvider == nil {\n\t\tmeterProvider = otel.GetMeterProvider()\n\t}\n\n\tmeter := meterProvider.Meter(\n\t\t\"github.com/redis/go-redis\",\n\t\tmetric.WithInstrumentationVersion(redis.Version()),\n\t)","sourceCodeStart":59,"sourceCodeEnd":95,"githubUrl":"https://github.com/go-redis/redis/blob/36d97525cd8076aed67cddf54778e9ea84550929/extra/redisotel-native/redisotel.go#L59-L95","documentation":"Returned by ObservabilityInstance.Init when the global OpenTelemetry observability singleton has already been initialized and Init is called again without an intervening Shutdown(). The singleton (guarded by observabilityInstanceOnce) attaches a metrics recorder to all Redis clients via redis.SetOTelRecorder, so a second Init would race with in-flight clients.","triggerScenarios":"Calling redisotel.GetObservabilityInstance().Init(cfg) twice in the same process — common in hot-reload (e.g. Air/plug, Neko dev-mode), tests that re-init per case without Shutdown, or shared-library code that initializes on import and again in main().","commonSituations":"Test suites reusing the global instance, serverless warm-starts that re-run setup, or multiple modules each calling Init defensively.","solutions":["Call Init exactly once at process startup; guard with IsEnabled() before calling.","In tests or reload paths, call GetObservabilityInstance().Shutdown() before re-Init.","If you need isolated instances, refactor to avoid the global singleton for tests."],"exampleFix":"// before\nredisotel.GetObservabilityInstance().Init(cfg1)\nredisotel.GetObservabilityInstance().Init(cfg2) // errors\n// after\ninst := redisotel.GetObservabilityInstance()\nif !inst.IsEnabled() {\n    inst.Init(cfg)\n}","handlingStrategy":"validation","validationCode":"inst := redisotel.GetObservabilityInstance()\nif !inst.IsEnabled() {\n    if err := inst.Init(cfg); err != nil {\n        return err\n    }\n}","typeGuard":"func mustInitObservability(cfg *redisotel.Config) error {\n    inst := redisotel.GetObservabilityInstance()\n    if inst.IsEnabled() {\n        return nil\n    }\n    return inst.Init(cfg)\n}","tryCatchPattern":"if err := inst.Init(cfg); err != nil {\n    if strings.Contains(err.Error(), \"already initialized\") {\n        return nil // acceptable: already set up\n    }\n    return err\n}","preventionTips":["Call Init exactly once at startup, guarded by IsEnabled().","In tests, Shutdown() in TestMain or t.Cleanup before re-init.","Avoid libraries calling Init defensively on import."],"tags":["otel","redisotel","observability","singleton","init"],"analyzedSha":"36d97525cd8076aed67cddf54778e9ea84550929","analyzedAt":"2026-08-06T01:08:27.376Z","schemaVersion":2}