cjpais/Handy · error · anyhow::Error

Device index {index} has kind '{other}', which cannot host a

Error message

Device index {index} has kind '{other}', which cannot host a model

What it means

resolve_device_index() found a device with the requested index, but its kind is not one of the four kinds Handy can map to a transcribe-cpp Backend (cpu, metal, cuda, vulkan). The registry advertises a device kind this Handy build cannot host a whisper model on — e.g. a new/preview backend kind registered by transcribe-cpp that the mapping here does not (yet) support.

Source

Thrown at src-tauri/src/managers/transcription.rs:1926

/// Resolve a `--list-devices` registry index to the (backend, gpu_device) pair
/// for a transcribe-cpp model load (the `--device-index` flag). The
/// backend is set explicitly from the device's kind, so there's no "index 0 =
/// auto" ambiguity. Errors if the index isn't a registered, loadable device.
fn resolve_device_index(index: usize) -> Result<(Backend, i32)> {
    let device = transcribe_compute_devices()
        .into_iter()
        .find(|d| d.index == Some(index))
        .ok_or_else(|| {
            anyhow::anyhow!("No compute device with index {index} (see --list-devices)")
        })?;
    let backend = match device.kind.as_str() {
        "cpu" => Backend::Cpu,
        "metal" => Backend::Metal,
        "cuda" => Backend::Cuda,
        "vulkan" => Backend::Vulkan,
        other => {
            return Err(anyhow::anyhow!(
                "Device index {index} has kind '{other}', which cannot host a model"
            ))
        }
    };
    // gpu_device is a registry index used only by GPU backends; CPU ignores it.
    let gpu_device = if matches!(backend, Backend::Cpu) {
        0
    } else {
        index as i32
    };
    Ok((backend, gpu_device))
}

/// Map Handy's whisper accelerator setting to a transcribe-cpp [`Backend`].
///
/// `Auto` lets the library pick the best device (with CPU fallback). `Cpu` forces
/// strict CPU. `Gpu` requests the platform GPU backend, but only if a device for
/// it is actually registered — otherwise it falls back to `Auto` so the load

View on GitHub (pinned to 98a4d80cce)

Solutions

  1. Run --list-devices and pick an index whose kind= is cpu, cuda, vulkan, or metal
  2. Omit --device-index and use the accelerator setting instead, which routes through select_transcribe_backend's supported candidates
  3. Update Handy — new backend kinds get mapped as support is added
  4. If you control the build, extend the match in resolve_device_index with the new Backend variant

Example fix

// before (mapping in resolve_device_index)
let backend = match device.kind.as_str() {
    "cpu" => Backend::Cpu,
    "metal" => Backend::Metal,
    "cuda" => Backend::Cuda,
    "vulkan" => Backend::Vulkan,
    other => return Err(anyhow::anyhow!("Device index {index} has kind '{other}', which cannot host a model")),
};

// after — support the new kind once transcribe-cpp exposes a Backend for it
    "opencl" => Backend::OpenCl,
// (and prefer selecting a supported kind via --list-devices until then)
Defensive patterns

Strategy: validation

Validate before calling

// Reject unsupported kinds before attempting the load
const HOSTABLE: [&str; 4] = ["cpu", "metal", "cuda", "vulkan"];
let device = transcribe_compute_devices().into_iter().find(|d| d.index == Some(index))
    .ok_or_else(|| anyhow::anyhow!("No compute device with index {index} (see --list-devices)"))?;
anyhow::ensure!(HOSTABLE.contains(&device.kind.as_str()),
    "device {index} kind '{}' cannot host a model; pick cpu/cuda/vulkan/metal from --list-devices", device.kind);

Type guard

// Narrow to devices Handy can actually host a whisper model on
fn hostable_device(index: usize) -> Option<ComputeDevice> {
    transcribe_compute_devices().into_iter()
        .find(|d| d.index == Some(index) && matches!(d.kind.as_str(), "cpu" | "metal" | "cuda" | "vulkan"))
}

Try / catch

match tm.load_model_with_device(&model_id, Some(index)) {
    Err(e) if e.to_string().contains("cannot host a model") => {
        // fall back to the persisted accelerator setting instead of a pinned device
        tm.load_model(&model_id)?
    }
    other => other?,
}

Prevention

When it happens

Trigger: --device-index N resolves to a device whose kind string falls into the `other` arm of the match (anything except cpu/metal/cuda/vulkan): a newly introduced transcribe-cpp backend kind in a newer library, or an experimental/preview device registration.

Common situations: A transcribe-cpp update registers additional backend kinds (e.g. OpenCL-class devices) that Handy's mapping predates; mixing library versions; selecting an exotic device listed by --list-devices without checking its kind column.

Related errors


AI-assisted analysis of cjpais/Handy@98a4d80cce (2026-08-16). Data as JSON: /api/errors/8807a69295c8e6af. Report an issue: GitHub.