{"record":{"id":"27fc66b21c1c9760","repo":"sgl-project/sglang","slug":"mlx-float64-arrays-cannot-be-exported-to-a-torch-m","errorCode":null,"errorMessage":"MLX float64 arrays cannot be exported to a Torch MPS tensor; use float32/bfloat16 or request device='cpu'","messagePattern":"MLX float64 arrays cannot be exported to a Torch MPS tensor; use float32/bfloat16 or request device='cpu'","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"python/sglang/srt/utils/tensor_bridge.py","lineNumber":266,"sourceCode":"\ndef _prepare_mlx_export(\n    array: mx.array,\n    target_device: torch.device,\n    mx: Any,\n) -> mx.array:\n    \"\"\"Prepare one lazy MLX result for the requested Torch target.\n\n    This intentionally does not evaluate the result.  Callers which export\n    several results should prepare every result first and then issue one\n    shared ``mx.eval`` boundary.\n    \"\"\"\n    if target_device.type not in {\"cpu\", \"mps\"}:\n        raise ValueError(\n            f\"The MLX tensor bridge supports CPU and MPS targets, got {target_device}\"\n        )\n\n    if target_device.type == \"mps\" and array.dtype == mx.float64:\n        raise ValueError(\n            \"MLX float64 arrays cannot be exported to a Torch MPS tensor; \"\n            \"use float32/bfloat16 or request device='cpu'\"\n        )\n\n    return array\n\n\ndef _has_negative_stride(array: mx.array) -> bool:\n    \"\"\"Return whether an evaluated MLX array has a DLPack-incompatible view.\"\"\"\n    # PyTorch's DLPack importer aborts the process for negative strides.  MLX\n    # exposes the evaluated layout through the buffer protocol, so inspect it\n    # before handing the capsule to PyTorch.\n    with memoryview(array) as view:\n        return any(stride < 0 for stride in (view.strides or ()))\n\n\ndef _export_evaluated_mlx(\n    array: mx.array,","sourceCodeStart":248,"sourceCodeEnd":284,"githubUrl":"https://github.com/sgl-project/sglang/blob/0132848349585cfe6aae51c4941cbae872505f8a/python/sglang/srt/utils/tensor_bridge.py#L248-L284","documentation":"Metal (MPS) does not support float64, so exporting an MLX float64 array to an MPS torch tensor is rejected with guidance to downcast or target CPU. The check is in _prepare_mlx_export, before any evaluation boundary.","triggerScenarios":"An MLX op producing float64 (e.g. from a CPU float64 input) exported with target device mps.","commonSituations":"Numeric/spectral workloads keeping float64 precision on the CPU stream, then trying to land the result back on Metal.","solutions":["Cast the MLX array to float32/bfloat16 before export: arr.astype(mx.float32)","Export with device='cpu' to keep float64 on CPU"],"exampleFix":"# before\nt = mlx_to_torch(arr, device='mps')  # arr is float64\n# after\nt = mlx_to_torch(arr.astype(mx.float32), device='mps')\n# or: t = mlx_to_torch(arr, device='cpu')","handlingStrategy":"type-guard","validationCode":"if target == \"mps\" and arr.dtype == mx.float64:\n    arr = arr.astype(mx.float32)  # or target cpu","typeGuard":"def exportable(arr, target: str) -> bool:\n    return not (target == \"mps\" and arr.dtype == mx.float64)","tryCatchPattern":null,"preventionTips":["Downcast float64 to float32 before Metal export","Keep high-precision results on the CPU stream"],"tags":["sglang","mlx","float64","mps","dtype"],"backgroundTag":"unsupported-dtype-conversion","analyzedSha":"0132848349585cfe6aae51c4941cbae872505f8a","analyzedAt":"2026-08-28T05:10:05.995Z","schemaVersion":2},"datasetVersion":"2026-08-28T06:17:29.519Z"}