huggingface/candle · error

unsupported const-set f8e4m3

Error message

unsupported const-set f8e4m3

What it means

This error is thrown by candle's Metal backend when a constant-fill (const_set / fill_) operation is requested on an F8E4M3 (8-bit float) tensor. The Metal GPU kernels that write a scalar constant into a buffer are only generated for F16, BF16, F32, I64, U32 and U8, so F8E4M3 has no kernel to dispatch and the backend bails out instead of silently producing wrong data. It is a deliberate unimplemented-feature guard, not a user error in arguments.

Source

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

            l: &Layout,
        ) -> Result<()> {
            let device = self_.device();
            let dtype = self_.dtype;
            let shape = l.shape();
            let el_count = shape.elem_count();
            let encoder = device.command_encoder()?;
            let dst = buffer_o(&self_.buffer, l, self_.dtype);

            if l.is_contiguous() {
                use candle_metal_kernels::unary::contiguous;
                let kernel_name = match dtype {
                    DType::F16 => contiguous::const_set::HALF,
                    DType::BF16 => contiguous::const_set::BFLOAT,
                    DType::F32 => contiguous::const_set::FLOAT,
                    DType::I64 => contiguous::const_set::I64,
                    DType::U32 => contiguous::const_set::U32,
                    DType::U8 => contiguous::const_set::U8,
                    DType::F8E4M3 => crate::bail!("unsupported const-set f8e4m3"),
                    DType::F64 => crate::bail!("unsupported const-set f64"),
                    DType::F4
                    | DType::F6E2M3
                    | DType::F6E3M2
                    | DType::F8E8M0
                    | DType::I16
                    | DType::I32 => {
                        return Err(Error::UnsupportedDTypeForOp(dtype, "const-set").bt())
                    }
                };
                candle_metal_kernels::call_const_set_contiguous(
                    &device.device,
                    &encoder,
                    &device.kernels,
                    kernel_name,
                    dtype.size_in_bytes(),
                    el_count,
                    s,

View on GitHub (pinned to d5fee525bf)

Solutions

  1. Fill the tensor in a supported dtype (e.g. F32) and then convert with to_dtype(DType::F8E4M3).
  2. Create the F8E4M3 tensor on the CPU, fill it there, then move it to the Metal device with .to_device().
  3. Use a construction API that writes data directly (Tensor::from_vec / from_slice) instead of const fill.
  4. Contribute or wait for an F8E4M3 const-set Metal kernel in candle_metal_kernels.

Example fix

// before
let t = Tensor::zeros((1024,), DType::F8E4M3, &device)?;
t.fill_(0.5f64)?; // panics/errors: unsupported const-set f8e4m3
// after
let t = Tensor::zeros((1024,), DType::F32, &device)?;
t.fill_(0.5f64)?;
let t = t.to_dtype(DType::F8E4M3, device)?;
Defensive patterns

Strategy: validation

Validate before calling

fn metal_const_set_supported(t: &candle_core::Tensor) -> Result<(), String> {
    use candle_core::DType;
    match t.dtype() {
        DType::F16 | DType::BF16 | DType::F32 | DType::I64 | DType::U32 | DType::U8 => Ok(()),
        other => Err(format!("const-set on Metal unsupported for dtype {:?}; fill in F32 then convert", other)),
    }
}

Type guard

fn is_metal_fill_dtype(d: candle_core::DType) -> bool {
    use candle_core::DType::*;
    matches!(d, F16 | BF16 | F32 | I64 | U32 | U8)
}

Try / catch

match t.fill_(v) {
    Ok(t) => t,
    Err(e) if e.to_string().contains("unsupported const-set") => {
        let mut t = Tensor::zeros(t.shape(), DType::F32, t.device())?;
        t.fill_(v)?;
        t.to_dtype(DType::F8E4M3, t.device())?
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Calling Tensor::fill_ / const_set (e.g. via fill_, ones_like-with-fill, zero_-style in-place init) with deviceMetal on a tensor whose dtype is DType::F8E4M3, either on a contiguous layout (metal_backend/mod.rs:479) or a strided one (mod.rs:510).

Common situations: Quantized-model workloads on Apple Silicon: creating/initializing FP8 (F8E4M3) weights or scale buffers on a Metal device, converting a checkpoint to F8E4M3 and then initializing it with a constant, or generic code that fills a tensor without checking whether its dtype is Metal-supported.

Related errors


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