{"record":{"id":"94e633bdad80029c","repo":"tracel-ai/burn","slug":"device-index-must-be-non-negative","errorCode":null,"errorMessage":"device index must be non-negative","messagePattern":"device index must be non-negative","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/burn-tensor/src/device.rs","lineNumber":238,"sourceCode":"        Self::Specified(i)\n    }\n}\n\nimpl From<u32> for DeviceIndex {\n    fn from(i: u32) -> Self {\n        Self::Specified(i as usize)\n    }\n}\n\nimpl From<u64> for DeviceIndex {\n    fn from(i: u64) -> Self {\n        Self::Specified(i as usize)\n    }\n}\n\nimpl From<i32> for DeviceIndex {\n    fn from(i: i32) -> Self {\n        Self::Specified(usize::try_from(i).expect(\"device index must be non-negative\"))\n    }\n}\n\nimpl From<i64> for DeviceIndex {\n    fn from(i: i64) -> Self {\n        Self::Specified(usize::try_from(i).expect(\"device index must be non-negative\"))\n    }\n}\n\n/// Selector for the more flexible backends whose device handle is a tagged\n/// enum (e.g. WGPU, which can target a discrete/integrated/virtual GPU, a CPU\n/// adapter, an externally-created wgpu setup, or just \"best available\").\n///\n/// The variants mirror `WgpuDevice` from cubecl so the mapping is direct, but\n/// it is kept as a burn-owned enum so callers don't have to depend on cubecl.\n#[derive(Clone, Debug, Hash, PartialEq, Eq, Default)]\npub enum DeviceKind {\n    /// Discrete GPU with the given index. The index is the index of the discrete GPU in the list","sourceCodeStart":220,"sourceCodeEnd":256,"githubUrl":"https://github.com/tracel-ai/burn/blob/d16f7ba2ed0d41408189384044cc886fb4c8f957/crates/burn-tensor/src/device.rs#L220-L256","documentation":"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.","triggerScenarios":"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').","commonSituations":"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.","solutions":["Validate the index is >= 0 before converting (e.g. with a guard or `if i >= 0`)","Fix upstream code producing -1 sentinel values (failed device detection) instead of passing it to DeviceIndex","Use the DeviceError/Result-based constructors or Default device selection when the index is unknown"],"exampleFix":"// before\ndevice.index = DeviceIndex::from(raw_id);\n// after\nlet idx = if raw_id >= 0 { DeviceIndex::from(raw_id) } else { DeviceIndex::Default };\ndevice.index = idx;","handlingStrategy":"validation","validationCode":"fn to_device_index(i: i32) -> Option<DeviceIndex> {\n    usize::try_from(i).ok().map(DeviceIndex::Specified)\n}","typeGuard":"fn valid_device_index(i: i32) -> bool { i >= 0 }","tryCatchPattern":"// panicking From; cannot catch - pre-validate instead\nif i < 0 { return Err(DeviceError::InvalidIndex(i)); }\nlet idx = DeviceIndex::from(i);","preventionTips":["Never forward -1 sentinel values from FFI into DeviceIndex","Wrap signed device ordinals in a validated conversion helper","Use Default device selection when the ordinal is unknown"],"tags":["device","panic","unsigned-conversion","burn-tensor"],"backgroundTag":"negative-device-index","analyzedSha":"d16f7ba2ed0d41408189384044cc886fb4c8f957","analyzedAt":"2026-09-05T13:19:14.260Z","contentChangedAt":"2026-09-05T13:19:14.260Z","schemaVersion":2},"datasetVersion":"2026-09-12T17:17:11.597Z"}