{"record":{"id":"a56a3f4c5e0e0339","repo":"sgl-project/sglang","slug":"sglang-use-mlx-requires-an-available-mlx-metal-dev","errorCode":null,"errorMessage":"SGLANG_USE_MLX requires an available MLX Metal device","messagePattern":"SGLANG_USE_MLX requires an available MLX Metal device","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"python/sglang/srt/hardware_backend/mlx/runtime.py","lineNumber":60,"sourceCode":"    if not _is_stable_series(\n        torch_version, _SUPPORTED_TORCH_SERIES\n    ) or not _is_stable_at_least(mlx_version, _MIN_MLX_VERSION):\n        raise RuntimeError(\n            \"SGLANG_USE_MLX requires stable Torch 2.13.x and MLX >= 0.32.0; \"\n            \"found \"\n            f\"Torch {torch_version or 'unknown'} + MLX {mlx_version or 'unknown'}; \"\n            \"reinstall with the srt_mps extra\"\n        )\n\n    mps_backend = getattr(torch.backends, \"mps\", None)\n    is_mps_available = getattr(mps_backend, \"is_available\", None)\n    if not callable(is_mps_available) or not is_mps_available():\n        raise RuntimeError(\"SGLANG_USE_MLX requires an available PyTorch MPS device\")\n\n    metal = getattr(mx, \"metal\", None)\n    is_available = getattr(metal, \"is_available\", None)\n    if not callable(is_available) or not is_available():\n        raise RuntimeError(\"SGLANG_USE_MLX requires an available MLX Metal device\")\n\n\n@lru_cache(maxsize=1)\ndef use_mlx() -> bool:\n    \"\"\"Return whether the validated MLX backend was explicitly enabled.\"\"\"\n    enabled = bool(envs.SGLANG_USE_MLX.get())\n    if enabled:\n        _validate_runtime()\n    return enabled\n","sourceCodeStart":42,"sourceCodeEnd":70,"githubUrl":"https://github.com/sgl-project/sglang/blob/0132848349585cfe6aae51c4941cbae872505f8a/python/sglang/srt/hardware_backend/mlx/runtime.py#L42-L70","documentation":"Final device check in the MLX validator: after Torch MPS passes, mlx.core.metal.is_available() must also report an available Metal device. This fires when the MLX package imports but cannot see a usable Metal GPU — typical on non-Apple platforms, VMs without GPU passthrough, or broken/older MLX builds.","triggerScenarios":"SGLANG_USE_MLX=1 where mlx.core.metal is missing or metal.is_available() is not callable/returns False — e.g. MLX CPU-only build, macOS VM without Metal, headless CI macOS runner without GPU, or a stale MLX older than the Metal API.","commonSituations":"Running in GitHub Actions macOS runners (no GPU), VMs, or after installing an unofficial mlx fork; also when mlx is present but torch passed via MPS while MLX was built without Metal support.","solutions":["Run on real Apple Silicon hardware with a Metal-capable GPU","Upgrade MLX to >= 0.32.0 via pip install -U 'mlx>=0.32.0' so the metal module exists","Verify with python -c \"import mlx.core as mx; print(mx.metal.is_available())\"","Unset SGLANG_USE_MLX in CI/headless environments"],"exampleFix":"# before\nexport SGLANG_USE_MLX=1  # in headless CI\n# after\npython -c \"import mlx.core as mx; assert mx.metal.is_available()\" || unset SGLANG_USE_MLX","handlingStrategy":"validation","validationCode":"def mlx_metal_available() -> bool:\n    import mlx.core as mx\n    fn = getattr(getattr(mx, \"metal\", None), \"is_available\", None)\n    return callable(fn) and fn()","typeGuard":null,"tryCatchPattern":"try:\n    use_mlx()\nexcept RuntimeError as e:\n    if \"MLX Metal device\" in str(e):\n        logger.error(\"No Metal GPU for MLX; disabling MLX backend\")\n        os.environ.pop(\"SGLANG_USE_MLX\", None)","preventionTips":["Preflight mx.metal.is_available() in launch scripts","Skip MLX on headless CI macOS runners","Keep mlx >= 0.32.0 so the metal module exists"],"tags":["mlx","metal","apple-silicon","device-unavailable","sglang"],"backgroundTag":"device-not-available","analyzedSha":"0132848349585cfe6aae51c4941cbae872505f8a","analyzedAt":"2026-08-28T05:10:05.995Z","schemaVersion":2},"datasetVersion":"2026-08-28T06:17:29.519Z"}