huggingface/candle · error

Invalid where: different dtypes for values {:?} != {:?}

Error message

Invalid where: different dtypes for values {:?} != {:?}

What it means

where_cond selects elements from a true-branch and false-branch tensor based on a condition; both value tensors must have the same dtype. The Metal backend explicitly checks t.dtype() != f.dtype() and bails with this message before dispatching the kernel.

Source

Thrown at candle-core/src/metal_backend/mod.rs:866

        t: &Self,
        t_l: &Layout,
        f: &Self,
        f_l: &Layout,
    ) -> Result<Self> {
        let device = self.device.clone();
        let shape = t_l.shape();
        let dims = shape.dims();
        let el = shape.elem_count();
        let dtype = t.dtype;
        let buffer = self
            .device
            .new_buffer_builder()
            .with_size_for(el, dtype)
            .with_label("where")
            .build()?;
        let encoder = self.device.command_encoder()?;
        if t.dtype() != f.dtype() {
            crate::bail!(
                "Invalid where: different dtypes for values {:?} != {:?}",
                t.dtype(),
                f.dtype()
            );
        }
        let name = match (self.dtype, t.dtype()) {
            (DType::U8, DType::F32) => "where_u8_f32",
            (DType::U32, DType::F32) => "where_u32_f32",
            (DType::U8, DType::BF16) => "where_u8_bf16",
            (DType::U8, DType::F16) => "where_u8_f16",
            (DType::U8, DType::I64) => "where_u8_i64",
            (DType::U8, DType::U32) => "where_u8_u32",
            (DType::U8, DType::U8) => "where_u8_u8",
            (left, right) => crate::bail!("Metal where_cond {left:?} {right:?} not implemented"),
        };
        let src = buffer_o(&self.buffer, layout, self.dtype);
        let t = buffer_o(&t.buffer, t_l, t.dtype);
        let f = buffer_o(&f.buffer, f_l, f.dtype);

View on GitHub (pinned to d5fee525bf)

Solutions

  1. Cast one branch to match the other with to_dtype before where_cond
  2. Ensure both branches come from the same compute pipeline/dtype
  3. Cast both branches to F32, run where_cond, cast back

Example fix

// before
let out = cond.where_cond(&a, &b.to_dtype(DType::F16)?)?; // a is F32
// after
let out = cond.where_cond(&a, &b.to_dtype(DType::F32)?)?;
Defensive patterns

Strategy: validation

Validate before calling

if cond_t.dtype() != a.dtype() || cond_t.dtype() != b.dtype() {
    anyhow::bail!("where_cond branches must share dtype");
}
// or normalize:
let b = b.to_dtype(a.dtype())?;
let out = cond_t.where_cond(&a, &b)?;

Try / catch

match cond.where_cond(&a, &b) {
    Ok(y) => y,
    Err(e) if e.to_string().contains("different dtypes for values") => {
        cond.where_cond(&a, &b.to_dtype(a.dtype())?)
    }
    Err(e) => return Err(e.into()),
}

Prevention

When it happens

Trigger: Calling Tensor::where_cond on Metal with a true tensor and false tensor of different dtypes, e.g. cond.where_cond(&f32_tensor, &f16_tensor)?.

Common situations: Mixing an fp32 bias branch with an fp16 model output; merging an integer index tensor with a float tensor; results of differently-typed branches in conditional logic.

Related errors


AI-assisted analysis of huggingface/candle@d5fee525bf (2026-09-02). Data as JSON: /api/errors/e203182dbc17a5e2. Report an issue: GitHub.