Lightning-AI/pytorch-lightning · error · TypeError

Device IDs (GPU/TPU) must be an int, a string, a sequence of

Error message

Device IDs (GPU/TPU) must be an int, a string, a sequence of ints, but you passed None

What it means

_check_data_type validates the devices argument type before parsing. None is not a valid device specification (int, str, or sequence of ints are), so passing devices=None (as opposed to omitting it or using 'auto') raises TypeError. It is raised from both the GPU parser (_parse_gpu_ids) and the TPU parser (_parse_tpu_devices).

Source

Thrown at src/lightning/fabric/utilities/device_parser.py:199

    """
    if len(device_ids) != len(set(device_ids)):
        raise MisconfigurationException("Device ID's (GPU) must be unique.")


def _check_data_type(device_ids: object) -> None:
    """Checks that the device_ids argument is one of the following: int, string, or sequence of integers.

    Args:
        device_ids: gpus/tpu_cores parameter as passed to the Trainer

    Raises:
        TypeError:
            If ``device_ids`` of GPU/TPUs aren't ``int``, ``str`` or sequence of ``int```

    """
    msg = "Device IDs (GPU/TPU) must be an int, a string, a sequence of ints, but you passed"
    if device_ids is None:
        raise TypeError(f"{msg} None")
    if isinstance(device_ids, (MutableSequence, tuple)):
        for id_ in device_ids:
            id_type = type(id_)  # because `isinstance(False, int)` -> True
            if id_type is not int:
                raise TypeError(f"{msg} a sequence of {type(id_).__name__}.")
    elif type(device_ids) not in (int, str):
        raise TypeError(f"{msg} {device_ids!r}.")


def _select_auto_accelerator() -> str:
    """Choose the accelerator type (str) based on availability."""
    from lightning.fabric.accelerators.cuda import CUDAAccelerator
    from lightning.fabric.accelerators.mps import MPSAccelerator
    from lightning.fabric.accelerators.xla import XLAAccelerator

    if XLAAccelerator.is_available():
        return "tpu"
    if MPSAccelerator.is_available():

View on GitHub (pinned to 9fed5c27d2)

Solutions

  1. Set devices explicitly: an int (e.g. 1), a string ('0,1'), or 'auto'
  2. If devices is optional in your config, default it to 'auto' or 1 instead of None
  3. Check env vars: devices=os.getenv('DEVICES', 'auto')

Example fix

# before
fabric = Fabric(accelerator="gpu", devices=os.getenv("N_GPUS"))  # None if unset

# after
fabric = Fabric(accelerator="gpu", devices=os.getenv("N_GPUS", "auto"))
Defensive patterns

Strategy: type-guard

Validate before calling

import os
devices = os.getenv("DEVICES", "auto")
assert devices is not None, "devices must be int, str, or sequence of ints, not None"

Type guard

def valid_devices(d) -> bool:
    if d is None: return False
    if isinstance(d, int) and not isinstance(d, bool): return True
    if isinstance(d, str): return True
    return isinstance(d, (list, tuple)) and all(type(x) is int for x in d)

Prevention

When it happens

Trigger: Fabric(devices=None) or Trainer(devices=None); passing a variable that defaults to None and was never set, e.g. devices=os.getenv('DEVICES') with the env var undefined; forwarding None from a config system (YAML/Hydra) where devices was left empty.

Common situations: Optional config fields that resolve to None; env-var-driven configs with missing variables; Hydra/OmegaConf merges that null out devices.

Related errors


AI-assisted analysis of Lightning-AI/pytorch-lightning@9fed5c27d2 (2026-08-28). Data as JSON: /api/errors/05e81e7b1a8fb8a1. Report an issue: GitHub.