{"record":{"id":"2340bdeeaf02505b","repo":"sgl-project/sglang","slug":"sgl-kernel-metal-is-importable-but-the-native-met","errorCode":null,"errorMessage":"sgl_kernel.metal is importable, but the native Metal extension or metallib is not available.${reason} Install the Metal kernels with `uv run python/sglang/kernels/aot/setup_metal.py install` from the SGLang repo root in the active environment.","messagePattern":"sgl_kernel\\.metal is importable, but the native Metal extension or metallib is not available\\.(.+?) Install the Metal kernels with `uv run python/sglang/kernels/aot/setup_metal\\.py install` from the SGLang repo root in the active environment\\.","errorType":"error_code","errorClass":"ImportError","httpStatus":null,"severity":"critical","filePath":"python/sglang/srt/hardware_backend/mlx/aot.py","lineNumber":28,"sourceCode":"\nfrom sglang.srt.environ import envs\n\nlogger = logging.getLogger(__name__)\n\n\ndef _load_metal_rope_pool_fused():\n    try:\n        from sgl_kernel import metal\n    except ImportError as exc:\n        raise ImportError(\n            \"sgl_kernel.metal is not importable. Install sgl-kernel in the \"\n            \"active environment before enabling SGLANG_MLX_USE_CUSTOM_ROPE.\"\n        ) from exc\n\n    import_error = getattr(metal, \"_IMPORT_ERROR\", None)\n    if getattr(metal, \"_metal\", None) is None or import_error is not None:\n        reason = f\" Reason: {import_error}.\" if import_error is not None else \"\"\n        raise ImportError(\n            \"sgl_kernel.metal is importable, but the native Metal extension \"\n            f\"or metallib is not available.{reason} Install the Metal kernels \"\n            \"with `uv run python/sglang/kernels/aot/setup_metal.py install` \"\n            \"from the SGLang repo root in the active environment.\"\n        ) from import_error\n    return metal.rope_pool_fused\n\n\n@dataclass\nclass MlxAOTRoPEKernel:\n    base: float = 0.0\n    config: dict[str, Any] = field(default_factory=dict)\n    rope_pool_fused: Optional[Any] = None\n\n    @property\n    def enabled(self) -> bool:\n        return (\n            self.base > 0.0 and bool(self.config) and self.rope_pool_fused is not None","sourceCodeStart":10,"sourceCodeEnd":46,"githubUrl":"https://github.com/sgl-project/sglang/blob/0132848349585cfe6aae51c4941cbae872505f8a/python/sglang/srt/hardware_backend/mlx/aot.py#L10-L46","documentation":"SGLang's MLX backend optionally uses a custom fused RoPE kernel loaded from a prebuilt Metal extension (`sgl_kernel.metal`). The Python module imports, but the underlying native extension or .metallib artifact is missing (a `_IMPORT_ERROR` is recorded on the module), so the loader raises ImportError instead of returning `metal.rope_pool_fused`. This is an install/environment-completeness error, not a code bug.","triggerScenarios":"Enabling SGLANG_MLX_USE_CUSTOM_ROPE (or otherwise triggering `_load_metal_rope_pool_fused` via `_build_rope_kernel`) in an environment where `sgl_kernel.metal` imports but `metal._metal` is None or `metal._IMPORT_ERROR` is set — e.g. the package was installed without building/downloading the metallib, or the AOT build step was skipped.","commonSituations":"Running on Apple Silicon with the MLX backend after a partial install (pip wheel without Metal artifacts), switching uv environments so the metallib built in one venv is missing in another, or after upgrading sgl-kernel without re-running the Metal AOT setup.","solutions":["Run `uv run python/sglang/kernels/aot/setup_metal.py install` from the SGLang repo root in the active environment.","Verify the install by checking `import sgl_kernel.metal as m; m._metal is not None and m._IMPORT_ERROR is None`.","If you don't need the fused kernel, unset SGLANG_MLX_USE_CUSTOM_ROPE to fall back to the non-AOT path.","Rebuild in the correct virtualenv — the metallib is per-environment; rebuilding in one venv does not fix another."],"exampleFix":"# before\nexport SGLANG_MLX_USE_CUSTOM_ROPE=1\npython -c \"from sglang.srt.hardware_backend.mlx.aot import _load_metal_rope_pool_fused; _load_metal_rope_pool_fused()\"  # ImportError\n\n# after\nuv run python/sglang/kernels/aot/setup_metal.py install\npython -c \"import sgl_kernel.metal as m; assert m._metal is not None\"","handlingStrategy":"validation","validationCode":"import sgl_kernel.metal as metal\nif getattr(metal, \"_metal\", None) is None or getattr(metal, \"_IMPORT_ERROR\", None):\n    raise SystemExit(\"Metal kernels missing; run setup_metal.py install\")","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Run setup_metal.py install as part of environment provisioning scripts.","Gate SGLANG_MLX_USE_CUSTOM_ROPE on an import sanity check at startup.","Re-run the Metal install after switching uv/venv environments."],"tags":["mlx","metal","aot-kernel","apple-silicon","install"],"backgroundTag":"native-extension-missing","analyzedSha":"0132848349585cfe6aae51c4941cbae872505f8a","analyzedAt":"2026-08-28T05:10:05.995Z","schemaVersion":2},"datasetVersion":"2026-08-28T06:17:29.519Z"}