tracel-ai/burn · error

device index must be non-negative

Error message

device index must be non-negative

What it means

DeviceIndex::from(i32) panics when given a negative i32, because a device index is an unsigned concept that must be >= 0. usize::try_from(i) fails for negative values and the expect message surfaces this. It is a defensive guard against callers encoding invalid device IDs in signed types.

Source

Thrown at crates/burn-tensor/src/device.rs:238

        Self::Specified(i)
    }
}

impl From<u32> for DeviceIndex {
    fn from(i: u32) -> Self {
        Self::Specified(i as usize)
    }
}

impl From<u64> for DeviceIndex {
    fn from(i: u64) -> Self {
        Self::Specified(i as usize)
    }
}

impl From<i32> for DeviceIndex {
    fn from(i: i32) -> Self {
        Self::Specified(usize::try_from(i).expect("device index must be non-negative"))
    }
}

impl From<i64> for DeviceIndex {
    fn from(i: i64) -> Self {
        Self::Specified(usize::try_from(i).expect("device index must be non-negative"))
    }
}

/// Selector for the more flexible backends whose device handle is a tagged
/// enum (e.g. WGPU, which can target a discrete/integrated/virtual GPU, a CPU
/// adapter, an externally-created wgpu setup, or just "best available").
///
/// The variants mirror `WgpuDevice` from cubecl so the mapping is direct, but
/// it is kept as a burn-owned enum so callers don't have to depend on cubecl.
#[derive(Clone, Debug, Hash, PartialEq, Eq, Default)]
pub enum DeviceKind {
    /// Discrete GPU with the given index. The index is the index of the discrete GPU in the list

View on GitHub (pinned to d16f7ba2ed)

Solutions

  1. Validate the index is >= 0 before converting (e.g. with a guard or `if i >= 0`)
  2. Fix upstream code producing -1 sentinel values (failed device detection) instead of passing it to DeviceIndex
  3. Use the DeviceError/Result-based constructors or Default device selection when the index is unknown

Example fix

// before
device.index = DeviceIndex::from(raw_id);
// after
let idx = if raw_id >= 0 { DeviceIndex::from(raw_id) } else { DeviceIndex::Default };
device.index = idx;
Defensive patterns

Strategy: validation

Validate before calling

fn to_device_index(i: i32) -> Option<DeviceIndex> {
    usize::try_from(i).ok().map(DeviceIndex::Specified)
}

Type guard

fn valid_device_index(i: i32) -> bool { i >= 0 }

Try / catch

// panicking From; cannot catch - pre-validate instead
if i < 0 { return Err(DeviceError::InvalidIndex(i)); }
let idx = DeviceIndex::from(i);

Prevention

When it happens

Trigger: Calling DeviceIndex::from(-1_i32) or any negative i32; propagating an uninitialized/default -1 sentinel device ID from native library bindings (e.g. CUDA/wgpu wrappers that use -1 as 'no device').

Common situations: Interfacing with FFI code that returns -1 on failure and passing the result straight into burn device construction; config files or CLI args parsed as i32 containing negative values.

Related errors


AI-assisted analysis of tracel-ai/burn@d16f7ba2ed (2026-09-05). Data as JSON: /api/errors/94e633bdad80029c. Report an issue: GitHub.