{"record":{"id":"05a6b981d2f7b3b2","repo":"sgl-project/sglang","slug":"rayprometheusmetric-requires-ray-to-be-installed","errorCode":null,"errorMessage":"RayPrometheusMetric requires Ray to be installed. Install with: pip install 'ray[serve]'","messagePattern":"RayPrometheusMetric requires Ray to be installed\\. Install with: pip install 'ray\\[serve\\]'","errorType":"exception","errorClass":"ImportError","httpStatus":null,"severity":"error","filePath":"python/sglang/srt/observability/ray_wrappers.py","lineNumber":89,"sourceCode":"\n    Subclasses populate ``self.metric`` with a ``ray.util.metrics`` instance in\n    their ``__init__``. Shared behaviour:\n\n    * A ``ReplicaId`` tag is appended to every metric and populated at\n      instantiation (and again on each ``labels()`` call) so Ray-Serve replicas\n      are distinguishable on dashboards.\n    * ``labels()`` returns a fresh copy of the wrapper with its tags bound,\n      mirroring the ``prometheus_client`` pattern and avoiding state sharing\n      between concurrent emits.\n    * Metric names are sanitised to satisfy Ray's OpenTelemetry naming rule\n      (no ``:``, no other punctuation).\n    \"\"\"\n\n    _is_labeled: bool = False\n\n    def __init__(self) -> None:\n        if ray_metrics is None:\n            raise ImportError(\n                \"RayPrometheusMetric requires Ray to be installed. \"\n                \"Install with: pip install 'ray[serve]'\"\n            )\n        self.metric: Optional[Metric] = None\n        self._tags: dict = {\"ReplicaId\": _get_replica_id() or \"\"}\n\n    @staticmethod\n    def _get_tag_keys(labelnames: Optional[List[str]]) -> tuple:\n        labels = list(labelnames) if labelnames else []\n        labels.append(\"ReplicaId\")\n        return tuple(labels)\n\n    def _build_tags(self, *labels: str, **labelskwargs: str) -> dict:\n        if labels:\n            # The trailing entry of ``_tag_keys`` is always ``ReplicaId`` which we\n            # populate ourselves; positional args fill the preceding keys only.\n            expected = len(self.metric._tag_keys) - 1\n            if len(labels) != expected:","sourceCodeStart":71,"sourceCodeEnd":107,"githubUrl":"https://github.com/sgl-project/sglang/blob/0132848349585cfe6aae51c4941cbae872505f8a/python/sglang/srt/observability/ray_wrappers.py#L71-L107","documentation":"RayPrometheusMetric wraps Ray Serve's metrics API, which is only present when the ray package (with serve extras) is installed. If the ray import failed, the module-level ray_metrics is None and constructing this wrapper raises ImportError with install instructions.","triggerScenarios":"Instantiating RayPrometheusMetric in an environment where `import ray` (or its metrics module) failed — plain sglang install without ray.","commonSituations":"Deploying sglang with the ray observability path enabled (e.g. ray serve integration) but ray not in the image; slim Docker images; CI environments trimming optional deps.","solutions":["pip install 'ray[serve]' in the environment","Or disable the Ray metrics path / use the standard Prometheus metrics wrapper instead","Pin a ray version compatible with your sglang release"],"exampleFix":"# before: ImportError raised\nmetric = RayPrometheusMetric()\n# after\n# shell: pip install 'ray[serve]'\nmetric = RayPrometheusMetric()","handlingStrategy":"validation","validationCode":"try:\n    import ray.metrics  # or ray.serve\n    ray_ok = True\nexcept ImportError:\n    ray_ok = False\nmetric_cls = RayPrometheusMetric if ray_ok else StandardPrometheusMetric","typeGuard":null,"tryCatchPattern":"try:\n    m = RayPrometheusMetric()\nexcept ImportError:\n    m = StandardPrometheusMetric()  # fallback wrapper","preventionTips":["Install 'ray[serve]' in images that use the ray observability path","Feature-detect optional integrations at startup, not at first metric use"],"tags":["observability","ray","metrics","missing-dependency"],"backgroundTag":"missing-optional-dependency","analyzedSha":"0132848349585cfe6aae51c4941cbae872505f8a","analyzedAt":"2026-08-28T05:10:05.995Z","schemaVersion":2},"datasetVersion":"2026-08-28T06:17:29.519Z"}