huggingface/candle · error

Expected f32/f16

Error message

Expected f32/f16

What it means

This error is thrown by the quantized matmul fast-path ( QuantizedMatMul::cpu_fwd ) when the LHS activation tensor storage is neither F32 nor F16. The quantized CPU kernels (gemmv/gemm for QKK types) are only implemented for f32 and f16 activations, so any other dtype (e.g. bf16, u8, i64) reaching this op on CPU bails.

Solutions

  1. Convert the activation tensor to DType::F32 before the quantized matmul: tensor.to_dtype(DType::F32)?
  2. Alternatively convert to DType::F16 if the surrounding model uses half precision
  3. Check where the tensor dtype changed (e.g. a .to_dtype call or model config dtype) and keep activations f32/f16 for quantized layers

Example fix

// before
let x = x.to_dtype(DType::BF16)?;
let y = qmatmul.forward(&x)?;
// after
let x = x.to_dtype(DType::F32)?;
let y = qmatmul.forward(&x)?;
Defensive patterns

Strategy: validation

Validate before calling

if !matches!(x.dtype(), candle::DType::F32 | candle::DType::F16) {
    x = x.to_dtype(candle::DType::F32)?;
}
let y = qmatmul.forward(&x)?;

Type guard

fn is_quantized_mm_ok(t: &candle_core::Tensor) -> bool {
    matches!(t.dtype(), candle_core::DType::F32 | candle_core::DType::F16)
}

Try / catch

let y = qmatmul.forward(&x).or_else(|_| qmatmul.forward(&x.to_dtype(candle::DType::F32)?))?;

Prevention

When it happens

Trigger: Calling QMatMul::forward / Tensor::quantized_matmul on CPU with a left-hand tensor whose dtype is not F32 or F16, e.g. after .to_dtype(DType::BF16) or passing an integer/quantized tensor as the activation input.

Common situations: Loading a GGUF model and casting activations to bf16 for memory savings; accidentally feeding a quantized or integer tensor as the hidden-state input; mixing a dtype conversion (bf16) with quantized inference in candle.

Related errors


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

Appendix: source

Thrown at candle-core/src/quantized/mod.rs:991

                    (dst_shape.elem_count() / n, k, n),
                    slice,
                    &mut dst_storage,
                )?;
                Ok((crate::CpuStorage::F32(dst_storage), dst_shape))
            }
            DType::F16 => {
                let slice = storage.as_slice::<f16>()?;
                let slice =
                    &slice[layout.start_offset()..layout.start_offset() + src_shape.elem_count()];
                let mut dst_storage = vec![f16::ZERO; dst_shape.elem_count()];
                self_storage.matmul_t_f16(
                    (dst_shape.elem_count() / n, k, n),
                    slice,
                    &mut dst_storage,
                )?;
                Ok((crate::CpuStorage::F16(dst_storage), dst_shape))
            }
            _ => crate::bail!("Expected f32/f16"),
        }
    }

    fn metal_fwd(
        &self,
        storage: &crate::MetalStorage,
        layout: &crate::Layout,
    ) -> Result<(crate::MetalStorage, Shape)> {
        let self_storage = match &self.storage {
            QStorage::Metal(metal) => metal,
            _ => unreachable!("Cannot call metal matmul on non metal QTensor"),
        };
        self_storage.fwd(&self.shape, storage, layout)
    }

    fn cuda_fwd(
        &self,
        storage: &crate::CudaStorage,

View on GitHub (pinned to d5fee525bf)