{"record":{"id":"27ab1e9bdac090ea","repo":"unslothai/unsloth","slug":"invalid-gpu-ids-requested-ids-ids-must-be-physi","errorCode":null,"errorMessage":"Invalid gpu_ids {requested_ids}: IDs must be physical GPU IDs between 0 and {physical_gpu_count - 1}. Rejected IDs: {out_of_range}. Parent-visible GPUs: {parent_visible_ids}","messagePattern":"Invalid gpu_ids (.+?): IDs must be physical GPU IDs between 0 and (.+?)\\. Rejected IDs: (.+?)\\. Parent-visible GPUs: (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"studio/backend/utils/hardware/hardware.py","lineNumber":2805,"sourceCode":"\n    # Reject negative IDs.\n    negative_ids = [gpu_id for gpu_id in requested_ids if gpu_id < 0]\n    if negative_ids:\n        raise ValueError(\n            f\"Invalid gpu_ids {requested_ids}: GPU IDs must be non-negative. \"\n            f\"Rejected IDs: {negative_ids}. Parent-visible GPUs: {parent_visible_ids}\"\n        )\n\n    # Only enforce the physical upper bound when the count is reliable (nvidia-smi).\n    # A torch count reflects only visible devices, so it could falsely reject valid\n    # physical indices. The parent-visible check below is always authoritative.\n    if physical_gpu_count > 0 and parent_visible_ids:\n        max_parent_id = max(parent_visible_ids)\n        if physical_gpu_count > max_parent_id:\n            # Count is plausibly physical, so enforce it.\n            out_of_range = [gpu_id for gpu_id in requested_ids if gpu_id >= physical_gpu_count]\n            if out_of_range:\n                raise ValueError(\n                    f\"Invalid gpu_ids {requested_ids}: IDs must be physical GPU IDs \"\n                    f\"between 0 and {physical_gpu_count - 1}. \"\n                    f\"Rejected IDs: {out_of_range}. Parent-visible GPUs: {parent_visible_ids}\"\n                )\n\n    disallowed_ids = [gpu_id for gpu_id in requested_ids if gpu_id not in parent_visible_ids]\n    if disallowed_ids:\n        raise ValueError(\n            f\"Invalid gpu_ids {requested_ids}: requested GPUs {disallowed_ids} are \"\n            f\"outside the parent-visible set {parent_visible_ids}\"\n        )\n\n    return requested_ids\n\n\ndef _resolve_model_identifier_for_gpu_estimate(\n    model_name: str, hf_token: Optional[str] = None\n) -> str:","sourceCodeStart":2787,"sourceCodeEnd":2823,"githubUrl":"https://github.com/unslothai/unsloth/blob/203007d19051dcd2ae33876786d117c99f6b0368/studio/backend/utils/hardware/hardware.py#L2787-L2823","documentation":"Raised when a requested id is >= physical_gpu_count, but only when the count is trusted (sourced from nvidia-smi and plausibly physical: count > max parent-visible id). This guard prevents silently selecting nonexistent devices when torch's visible-only count would under-report. The message states the valid 0..count-1 range, the rejected ids, and the parent-visible set.","triggerScenarios":"Requesting gpu_ids=[2] on a 2-GPU machine (valid ids 0..1) where nvidia-smi reports physical_gpu_count=2; requesting an id valid on another machine after moving a config.","commonSituations":"Config written on an 8-GPU box reused on a 2-GPU box; misunderstanding that ids are physical indices not per-job slots; off-by-one from treating count as the last index.","solutions":["Use ids in [0, physical_gpu_count-1]; check nvidia-smi -L for the real count and ordinals.","If the machine genuinely has more GPUs, fix CUDA_VISIBLE_DEVICES hiding them and restart the parent process (masks are read at parent startup).","Prefer auto-selection (omit gpu_ids) unless specific placement is required.","Parameterize configs by hostname/GPU count instead of hardcoding id lists."],"exampleFix":"# before\nselect_gpus([2])  # 2-GPU machine -> ValueError (valid: 0..1)\n\n# after\nselect_gpus([0, 1])  # or omit ids for auto-select","handlingStrategy":"validation","validationCode":"import subprocess\n\ndef physical_gpu_count() -> int:\n    out = subprocess.run(\n        [\"nvidia-smi\", \"-L\"], capture_output=True, text=True\n    ).stdout\n    return sum(1 for line in out.splitlines() if line.startswith(\"GPU \"))\n\n# guard: assert all(0 <= i < physical_gpu_count() for i in gpu_ids)","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Check nvidia-smi -L for the physical count/ordinals before hardcoding ids.","Remember ids are 0-based physical indices; count is not a valid id.","Parameterize GPU configs per host instead of copying them across machines.","Prefer auto-selection when exact placement is not required."],"tags":["gpu","cuda","hardware","range-validation"],"backgroundTag":null,"analyzedSha":"203007d19051dcd2ae33876786d117c99f6b0368","analyzedAt":"2026-08-15T02:48:39.846Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}