huggingface/candle · error

Metal conv1d {dtype:?} not implemented

Error message

Metal conv1d {dtype:?} not implemented

What it means

conv1d on Metal is implemented via im2col1d kernels available only for F32, F16, BF16, U8 and U32. A conv1d on a tensor of any other dtype (e.g. I64) hits this bail before calling call_im2col1d_strided.

Source

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

        let dilation = params.dilation;
        let padding = params.padding;
        let k_size = params.k_size;
        let l_out = (dims[2] + 2 * padding - dilation * (k_size - 1) - 1) / stride + 1;
        let dst_el = dims[0] * l_out * dims[1] * k_size;
        let dst = self
            .device
            .new_buffer_builder()
            .with_size_for(dst_el, self.dtype)
            .with_label("conv1d_im2col")
            .build()?;
        let encoder = self.device.command_encoder()?;
        let name = match self.dtype {
            DType::F32 => "im2col1d_f32",
            DType::F16 => "im2col1d_f16",
            DType::BF16 => "im2col1d_bf16",
            DType::U8 => "im2col1d_u8",
            DType::U32 => "im2col1d_u32",
            dtype => crate::bail!("Metal conv1d {dtype:?} not implemented"),
        };
        let src = buffer_o(&self.buffer, layout, self.dtype);
        candle_metal_kernels::call_im2col1d_strided(
            &self.device.device,
            &encoder,
            &self.device.kernels,
            name,
            layout.shape().dims(),
            strides,
            (k_size, stride, padding, dilation),
            src,
            &dst,
        )
        .map_err(MetalError::from)?;
        drop(encoder);
        let col = Self {
            buffer: dst,
            device,

View on GitHub (pinned to d5fee525bf)

Solutions

  1. Cast the input (and weights) to F32/F16/BF16 before conv1d
  2. Fix upstream dtype handling so activations are float for conv layers
  3. Run conv1d on CPU and move results back to Metal

Example fix

// before
let y = x_i64.conv1d(&kernel, padding, stride, dilation, groups)?;
// after
let y = x_i64.to_dtype(DType::F32)?.conv1d(&kernel, padding, stride, dilation, groups)?;
Defensive patterns

Strategy: validation

Validate before calling

if !matches!(x.dtype(), DType::F32 | DType::F16 | DType::BF16 | DType::U8 | DType::U32) {
    x = x.to_dtype(DType::F32)?;
}
let y = x.conv1d(&kernel, p, s, d, g)?;

Try / catch

match x.conv1d(&k, p, s, d, g) {
    Ok(y) => y,
    Err(e) if e.to_string().contains("conv1d") && e.to_string().contains("not implemented") => {
        x.to_dtype(DType::F32)?.conv1d(&k.to_dtype(DType::F32)?, p, s, d, g)
    }
    Err(e) => return Err(e.into()),
}

Prevention

When it happens

Trigger: Calling Tensor::conv1d (or modules using it) on a Metal tensor whose dtype is not one of F32/F16/BF16/U8/U32 — practically only I64/F64-style inputs trigger it.

Common situations: Running integer embeddings directly through a 1D conv; dtype accidentally left as i64 after tokenization; model weights loaded with an unsupported dtype on Metal.

Related errors


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