{"id":"c0ed4e17ab3eca9e","repo":"redis/node-redis","slug":"opentelemetry-already-initialized","errorCode":null,"errorMessage":"OpenTelemetry already initialized","messagePattern":"OpenTelemetry already initialized","errorType":"exception","errorClass":"OpenTelemetryError","httpStatus":null,"severity":"error","filePath":"packages/client/lib/opentelemetry/index.ts","lineNumber":57,"sourceCode":"   *   exporter: new ConsoleMetricExporter()\n   * });\n   *\n   * const provider = new MeterProvider({ readers: [reader] });\n   * metrics.setGlobalMeterProvider(provider);\n   *\n   * OpenTelemetry.init({\n   *   metrics: {\n   *     enabled: true,\n   *     enabledMetricGroups: [\"pubsub\", \"connection-basic\", \"resiliency\"],\n   *     includeCommands: [\"GET\", \"SET\"],\n   *     hidePubSubChannelNames: true\n   *   }\n   * });\n   * ```\n   */\n  public static init(config: ObservabilityConfig) {\n    if (OpenTelemetry._instance) {\n      throw new OpenTelemetryError(\"OpenTelemetry already initialized\");\n    }\n\n    const api: OpenTelemetryApiModule = (() => {\n      try {\n        return require(\"@opentelemetry/api\");\n      } catch {\n        throw new OpenTelemetryError(\"@opentelemetry/api not found\");\n      }\n    })();\n\n    OpenTelemetry._instance = new OpenTelemetry();\n    ClientRegistry.init();\n    OTelMetrics.init({ api, config });\n  }\n}\n\nexport {\n  OTelClientAttributes,","sourceCodeStart":39,"sourceCodeEnd":75,"githubUrl":"https://github.com/redis/node-redis/blob/bb5beb56578573910e2ee8f39681edc214c41398/packages/client/lib/opentelemetry/index.ts#L39-L75","documentation":"OpenTelemetry is a singleton: OpenTelemetry.init() bootstraps the ClientRegistry and OTelMetrics once for the whole process. Calling init() a second time throws OpenTelemetryError because re-initializing would double-register diagnostics_channel subscribers and meter instruments, corrupting metrics.","triggerScenarios":"Calling OpenTelemetry.init(config) more than once in the same process; calling it again after a hot reload (HMR, tsx watch, jest resetModules without reset); init invoked in both a framework bootstrap and an app bootstrap.","commonSituations":"Multiple entry points (worker + server) sharing a process; test suites that re-import the redis module; dev servers with watch-mode reload that re-execute init; accidental double init in bootstrap ordering.","solutions":["Call OpenTelemetry.init() exactly once at process startup, guarded by a flag or the singleton check.","In tests, reset via OTelMetrics.reset() / module re-import discipline instead of calling init again.","If using HMR/watch, ensure the init call site is not re-executed on reload (move to a module evaluated once).","Guard with a check before calling: only init when not already initialized."],"exampleFix":"// before\nOpenTelemetry.init(config); // called in two places\n\n// after\nlet otelStarted = false;\nif (!otelStarted) { OpenTelemetry.init(config); otelStarted = true; }","handlingStrategy":"validation","validationCode":"let _otelInit = false;\nif (!_otelInit) { OpenTelemetry.init(config); _otelInit = true; }","typeGuard":null,"tryCatchPattern":"try { OpenTelemetry.init(config); } catch (e) { if (!/already initialized/.test(e.message)) throw e; }","preventionTips":["Initialize OTel exactly once at process entry.","In tests/HMR, reset (OTelMetrics.reset) rather than re-init.","Centralize init in a single bootstrap module."],"tags":["opentelemetry","singleton","initialization","observability"],"analyzedSha":"bb5beb56578573910e2ee8f39681edc214c41398","analyzedAt":"2026-08-03T19:09:15.686Z","schemaVersion":2}