deepset-ai/haystack · error · ValueError

Device id must be >= 0, got {id}

Error message

Device id must be >= 0, got {id}

What it means

Device.__init__ raises ValueError when a device id is provided that is negative. Device ids (GPU ordinal, XPU index, etc.) must be >= 0; only None is allowed for devices without an index (e.g. CPU).

Source

Thrown at haystack/utils/device.py:78

        The device type.
    :param id:
        The optional device id.
    """

    type: DeviceType
    id: int | None = field(default=None)

    def __init__(self, type: DeviceType, id: int | None = None) -> None:  # noqa:A002
        """
        Create a generic device.

        :param type:
            The device type.
        :param id:
            The device id.
        """
        if id is not None and id < 0:
            raise ValueError(f"Device id must be >= 0, got {id}")

        self.type = type
        self.id = id

    def __str__(self) -> str:
        if self.id is None:
            return str(self.type)
        return f"{self.type}:{self.id}"

    @staticmethod
    def cpu() -> "Device":
        """
        Create a generic CPU device.

        :returns:
            The CPU device.
        """
        return Device(DeviceType.CPU)

View on GitHub (pinned to e318778c9b)

Solutions

  1. Pass None instead of a negative number when the device has no id
  2. Fix the upstream logic that produced the sentinel (e.g. spaCy's -1 means CPU → use DeviceType.CPU with id None)
  3. Validate/parse the id before constructing Device

Example fix

// before
dev = Device(DeviceType.GPU, -1)
// after
dev = Device(DeviceType.CPU, None)  # or omit id for devices without an index
Defensive patterns

Strategy: validation

Validate before calling

def safe_device(dtype, id):
    if id is not None and id < 0:
        raise ValueError(f"refusing negative device id {id}")
    return Device(dtype, id)

Type guard

def is_valid_device_id(id: object) -> bool:
    return id is None or (isinstance(id, int) and not isinstance(id, bool) and id >= 0)

Try / catch

try:
    dev = Device(dtype, raw_id)
except ValueError as e:
    print(f"Invalid device id: {e}; falling back to CPU")
    dev = Device(DeviceType.CPU, None)

Prevention

When it happens

Trigger: Constructing Device(type, id) with a negative id, e.g. Device(DeviceType.GPU, -1) or parsing a device string with a negative ordinal; often results from sentinel values (-1) used elsewhere leaking into Device construction.

Common situations: Using -1 as a 'no device' sentinel from other libraries (spaCy uses -1 for CPU) and passing it to Device; parsing malformed config values like 'cuda:-1'.

Related errors


AI-assisted analysis of deepset-ai/haystack@e318778c9b (2026-08-30). Data as JSON: /api/errors/3e3333f607d4de0e. Report an issue: GitHub.