{"record":{"id":"99546dc6b9f2d380","repo":"redis/redis-py","slug":"metrics-are-enabled-but-no-global-meterprovider-is","errorCode":null,"errorMessage":"Metrics are enabled but no global MeterProvider is configured.\n\nSet up OpenTelemetry before initializing redis-py observability:\n\n  from opentelemetry import metrics\n  from opentelemetry.sdk.metrics import MeterProvider\n  from opentelemetry.sdk.metrics.export import PeriodicExportingMetricReader\n  from opentelemetry.exporter.otlp.proto.http.metric_exporter import OTLPMetricExporter\n\n  # Create exporter\n  exporter = OTLPMetricExporter(\n      endpoint='http://localhost:4318/v1/metrics'\n  )\n\n  # Create reader\n  reader = PeriodicExportingMetricReader(\n      exporter=exporter,\n      export_interval_millis=10000\n  )\n\n  # Create and set global provider\n  provider = MeterProvider(metric_readers=[reader])\n  metrics.set_meter_provider(provider)\n\n  # Now initialize redis-py observability\n  from redis.observability import get_observability_instance, OTelConfig\n  otel = get_observability_instance()\n  otel.init(OTelConfig(enable_metrics=True))","messagePattern":"Metrics are enabled but no global MeterProvider is configured\\.\n\nSet up OpenTelemetry before initializing redis-py observability:\n\n  from opentelemetry import metrics\n  from opentelemetry\\.sdk\\.metrics import MeterProvider\n  from opentelemetry\\.sdk\\.metrics\\.export import PeriodicExportingMetricReader\n  from opentelemetry\\.exporter\\.otlp\\.proto\\.http\\.metric_exporter import OTLPMetricExporter\n\n  # Create exporter\n  exporter = OTLPMetricExporter\\(\n      endpoint='http://localhost:4318/v1/metrics'\n  \\)\n\n  # Create reader\n  reader = PeriodicExportingMetricReader\\(\n      exporter=exporter,\n      export_interval_millis=10000\n  \\)\n\n  # Create and set global provider\n  provider = MeterProvider\\(metric_readers=\\[reader\\]\\)\n  metrics\\.set_meter_provider\\(provider\\)\n\n  # Now initialize redis-py observability\n  from redis\\.observability import get_observability_instance, OTelConfig\n  otel = get_observability_instance\\(\\)\n  otel\\.init\\(OTelConfig\\(enable_metrics=True\\)\\)","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"redis/observability/providers.py","lineNumber":90,"sourceCode":"            return None\n\n        # Lazy import - only import OTel when metrics are enabled\n        try:\n            from opentelemetry import metrics\n            from opentelemetry.metrics import NoOpMeterProvider\n        except ImportError:\n            raise ImportError(\n                \"OpenTelemetry is not installed. Install it with:\\n\"\n                \"  pip install opentelemetry-api opentelemetry-sdk opentelemetry-exporter-otlp-proto-http\"\n            )\n\n        # Get the global MeterProvider\n        if self._meter_provider is None:\n            self._meter_provider = metrics.get_meter_provider()\n\n            # Check if it's a real provider (not NoOp)\n            if isinstance(self._meter_provider, NoOpMeterProvider):\n                raise RuntimeError(\n                    \"Metrics are enabled but no global MeterProvider is configured.\\n\"\n                    \"\\n\"\n                    \"Set up OpenTelemetry before initializing redis-py observability:\\n\"\n                    \"\\n\"\n                    \"  from opentelemetry import metrics\\n\"\n                    \"  from opentelemetry.sdk.metrics import MeterProvider\\n\"\n                    \"  from opentelemetry.sdk.metrics.export import PeriodicExportingMetricReader\\n\"\n                    \"  from opentelemetry.exporter.otlp.proto.http.metric_exporter import OTLPMetricExporter\\n\"\n                    \"\\n\"\n                    \"  # Create exporter\\n\"\n                    \"  exporter = OTLPMetricExporter(\\n\"\n                    \"      endpoint='http://localhost:4318/v1/metrics'\\n\"\n                    \"  )\\n\"\n                    \"\\n\"\n                    \"  # Create reader\\n\"\n                    \"  reader = PeriodicExportingMetricReader(\\n\"\n                    \"      exporter=exporter,\\n\"\n                    \"      export_interval_millis=10000\\n\"","sourceCodeStart":72,"sourceCodeEnd":108,"githubUrl":"https://github.com/redis/redis-py/blob/6a6b581b48225afa0b76912d1028c6035baee932/redis/observability/providers.py#L72-L108","documentation":"Raised as RuntimeError by OTelProviderManager.get_meter_provider() (redis/observability/providers.py:90) when metrics are enabled and the SDK is importable, but the global MeterProvider is still the OpenTelemetry default NoOpMeterProvider. redis-py deliberately uses the application-owned global provider (see module docstring) rather than installing its own, so if nothing has called metrics.set_meter_provider(...) the manager refuses to silently no-op and raises with a copy-pasteable setup recipe.","triggerScenarios":"Calling otel.init(OTelConfig(enable_metrics=True)) and then a Redis operation without ever having called metrics.set_meter_provider(MeterProvider(metric_readers=[...])) first. The check is `isinstance(self._meter_provider, NoOpMeterProvider)` — so any real provider set before init avoids this, while an unset global defaults to NoOp and trips it.","commonSituations":"App initializes redis-py observability at import time but defers OTel SDK setup to a later app hook that runs after the first Redis command; a framework integration (e.g. FastAPI/Django startup) sets the provider in a different lifecycle stage than the one that constructs the Redis client; test code that enables metrics without wiring a provider; ordering bug where set_meter_provider runs after otel.init's first get_meter_provider().","solutions":["Set a real global MeterProvider BEFORE initializing redis-py observability, exactly as the embedded recipe shows: build an OTLPMetricExporter, wrap it in a PeriodicExportingMetricReader, construct MeterProvider(metric_readers=[reader]), then metrics.set_meter_provider(provider).","Reorder application startup so the OTel SDK/provider setup runs before get_observability_instance().init(...).","If you only want local/no-op metrics, disable metrics by passing OTelConfig(enabled_telemetry=[]) (or TelemetryOption(0)) so get_meter_provider() returns None before the NoOp check.","Confirm your provider is not a NoOpMeterProvider via `isinstance(metrics.get_meter_provider(), NoOpMeterProvider)` returns False after setup."],"exampleFix":"# before - metrics enabled, provider never set\nfrom redis.observability import get_observability_instance, OTelConfig\notel = get_observability_instance()\notel.init(OTelConfig(enable_metrics=True))  # first command -> providers.py:90 RuntimeError\n\n# after - set global provider first\nfrom opentelemetry import metrics\nfrom opentelemetry.sdk.metrics import MeterProvider\nfrom opentelemetry.sdk.metrics.export import PeriodicExportingMetricReader\nfrom opentelemetry.exporter.otlp.proto.http.metric_exporter import OTLPMetricExporter\nreader = PeriodicExportingMetricReader(\n    exporter=OTLPMetricExporter(endpoint='http://localhost:4318/v1/metrics'),\n    export_interval_millis=10000,\n)\nmetrics.set_meter_provider(MeterProvider(metric_readers=[reader]))\notel.init(OTelConfig(enable_metrics=True))","handlingStrategy":"validation","validationCode":"from opentelemetry import metrics\nfrom opentelemetry.metrics import NoOpMeterProvider\n\ndef real_provider_is_set():\n    return not isinstance(metrics.get_meter_provider(), NoOpMeterProvider)\n\n# set the provider, then verify, before initializing redis-py observability\nmetrics.set_meter_provider(MeterProvider(metric_readers=[reader]))\nassert real_provider_is_set(), 'global MeterProvider still NoOp'\notel.init(OTelConfig(enable_metrics=True))","typeGuard":null,"tryCatchPattern":"try:\n    otel.init(OTelConfig(enable_metrics=True))\nexcept RuntimeError as e:\n    if 'no global MeterProvider' in str(e):\n        logging.error('Set a global MeterProvider before enabling redis-py metrics')\n    else:\n        raise","preventionTips":["Always set metrics.set_meter_provider(...) before get_observability_instance().init(...).","Centralize OTel SDK setup in a single startup function that runs before any Redis client issues commands.","Assert isinstance(metrics.get_meter_provider(), NoOpMeterProvider) is False right after setup as a guard.","If metrics are optional in some environments, pass OTelConfig(enabled_telemetry=[]) instead of enable_metrics=True."],"tags":["observability","opentelemetry","provider","configuration","initialization-order","metrics"],"backgroundTag":null,"analyzedSha":"6a6b581b48225afa0b76912d1028c6035baee932","analyzedAt":"2026-08-10T12:52:44.840Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-21T04:17:39.646Z"}