{"record":{"id":"99806a253aadfae6","repo":"sgl-project/sglang","slug":"lplb-fused-solver-requires-cuda-tensors-got-a-on","errorCode":null,"errorMessage":"LPLB fused solver requires CUDA tensors; got A on {A.device}.","messagePattern":"LPLB fused solver requires CUDA tensors; got A on (.+?)\\.","errorType":"validation","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"python/sglang/kernels/ops/lplb/torch_solver.py","lineNumber":129,"sourceCode":"    Args:\n        A: Constraint matrix, shape (NC, NV), float32, on CUDA.\n        b: RHS vector, shape (NC,), float32, on CUDA.\n        c: Objective coefficients, shape (NV,), float32, on CUDA.\n        num_iters: Number of barrier iterations (default 5).\n\n    Returns:\n        x: Solution vector, shape (NV,), float32. The kernel writes 0.5\n        for every entry on non-convergence.\n    \"\"\"\n    nc, nv = A.shape\n    assert b.shape == (nc,), f\"b shape mismatch: {b.shape} vs ({nc},)\"\n    assert c.shape == (nv,), f\"c shape mismatch: {c.shape} vs ({nv},)\"\n\n    _init_fused_backend()\n    if not _FUSED_AVAILABLE:\n        raise RuntimeError(f\"LPLB fused solver unavailable: {_unavailable_reason()}\")\n    if not A.is_cuda:\n        raise RuntimeError(\n            f\"LPLB fused solver requires CUDA tensors; got A on {A.device}.\"\n        )\n    if A.dtype != torch.float32:\n        raise RuntimeError(\n            f\"LPLB fused solver requires float32; got A.dtype={A.dtype}.\"\n        )\n    return _FUSED_SOLVE_IPM(A, b, c, num_iters=num_iters)\n\n\ndef solve_ipm_torch_reference(\n    A: torch.Tensor,\n    b: torch.Tensor,\n    c: torch.Tensor,\n    num_iters: int = 5,\n) -> torch.Tensor:\n    \"\"\"Pure-torch reference for the fused IPM kernel — testing only.\n\n    Mirrors the barrier-method iteration in ``csrc/lplb/ipm.cuh``","sourceCodeStart":111,"sourceCodeEnd":147,"githubUrl":"https://github.com/sgl-project/sglang/blob/0132848349585cfe6aae51c4941cbae872505f8a/python/sglang/kernels/ops/lplb/torch_solver.py#L111-L147","documentation":"solve_ipm requires all inputs on CUDA; passing A on CPU (or any non-CUDA device) raises immediately. The fused kernel launches on the tensor's device with no host fallback.","triggerScenarios":"Calling solve_ipm(A, b, c) with A created via torch.randn(...) without .cuda(), or tensors left on 'cpu' after a checkpoint load; the check only inspects A.","commonSituations":"Prototype scripts that forgot .to('cuda'); models moved to GPU except one operand; b or c on CPU with A on GPU passes this check but may fail inside the kernel — always move all three.","solutions":["Move all inputs to the same CUDA device: A, b, c = A.cuda(), b.cuda(), c.cuda() (or .to(device))","Add an assert A.is_cuda before calling solve_ipm in your pipeline","Use solve_ipm_torch_reference for CPU-side debugging only"],"exampleFix":"// before\nx, y, s = solve_ipm(A, b, c)  # A on cpu\n\n// after\ndevice = 'cuda'\nx, y, s = solve_ipm(A.to(device), b.to(device), c.to(device))","handlingStrategy":"type-guard","validationCode":"device = dst_device if dst_device is not None else 'cuda'\nA, b, c = A.to(device), b.to(device), c.to(device)\nassert A.is_cuda","typeGuard":"def all_cuda(*ts: torch.Tensor) -> bool:\n    return all(t.is_cuda for t in ts)","tryCatchPattern":null,"preventionTips":["Centralize a single 'device' variable for each request/model and .to(device) every operand","Add startup asserts that model buffers and inputs share one device"],"tags":["device-mismatch","cuda","lplb"],"backgroundTag":"tensor-device-mismatch","analyzedSha":"0132848349585cfe6aae51c4941cbae872505f8a","analyzedAt":"2026-08-28T05:10:05.995Z","schemaVersion":2},"datasetVersion":"2026-08-28T06:17:29.519Z"}