huggingface/candle · error
Metal strided to_dtype {left:?} {right:?} not implemented
Error message
Metal strided to_dtype {left:?} {right:?} not implemented What it means
The strided (non-contiguous) Metal to_dtype path has its own kernel table; a cast between dtype pairs missing from that table triggers this bail. Strided layouts arise from slicing, transposing, or other view ops, so the same cast may work contiguous but fail strided.
Source
Thrown at candle-core/src/metal_backend/mod.rs:650
(DType::I64, DType::BF16) => "cast_i64_bf16_strided",
(DType::I64, DType::F16) => "cast_i64_f16_strided",
(DType::I64, DType::U32) => "cast_i64_u32_strided",
(DType::I64, DType::U8) => "cast_i64_u8_strided",
(DType::U32, DType::BF16) => "cast_u32_bf16_strided",
(DType::U32, DType::F16) => "cast_u32_f16_strided",
(DType::U32, DType::F32) => "cast_u32_f32_strided",
(DType::U32, DType::I64) => "cast_u32_i64_strided",
(DType::U32, DType::U8) => "cast_u32_u8_strided",
(DType::U8, DType::BF16) => "cast_u8_bf16_strided",
(DType::U8, DType::F16) => "cast_u8_f16_strided",
(DType::U8, DType::F32) => "cast_u8_f32_strided",
(DType::U8, DType::I64) => "cast_u8_i64_strided",
(DType::U8, DType::U32) => "cast_u8_u32_strided",
(left, right) => {
crate::bail!("Metal strided to_dtype {left:?} {right:?} not implemented")
}
};
candle_metal_kernels::call_cast_strided(
&device.device,
&encoder,
&device.kernels,
kernel_name,
layout.dims(),
src,
layout.stride(),
&buffer,
)
.map_err(MetalError::from)?;
}
Ok(Self::new(buffer, device.clone(), el_count, dtype))
}
fn unary_impl<B: UnaryOpT>(&self, layout: &Layout) -> Result<Self> {View on GitHub (pinned to d5fee525bf)
Solutions
- Make the tensor contiguous first: tensor.contiguous()?.to_dtype(dtype)?
- Cast before the op that creates the strided layout
- Cast on CPU and move back to Metal
- Use a dtype pair present in the strided cast table
Example fix
// before let t = tensor.transpose(0, 1)?.to_dtype(DType::F16)?; // after let t = tensor.transpose(0, 1)?.contiguous()?.to_dtype(DType::F16)?;
Defensive patterns
Strategy: fallback
Validate before calling
if !tensor.is_contiguous() {
tensor = tensor.contiguous()?; // use contiguous cast path
}
tensor = tensor.to_dtype(target)?; Try / catch
match strided_tensor.to_dtype(target) {
Ok(t) => t,
Err(e) if e.to_string().contains("strided to_dtype") => {
strided_tensor.contiguous()?.to_dtype(target)?
}
Err(e) => return Err(e.into()),
} Prevention
- Call .contiguous() after transpose/slice before dtype conversion
- Cast tensors while they are still contiguous in the dataflow
- Keep GPU tensors in dtypes with full strided cast coverage (F32/F16/BF16)
When it happens
Trigger: Calling to_dtype on a non-contiguous Metal tensor (e.g. after transpose/slice/narrow) with a dtype pair absent from the strided cast table.
Common situations: Casting a transposed activation map to fp16 on Metal; converting slices of embedding tables; working with permuted tensors in inference graphs.
Related errors
- Metal contiguous to_dtype {left:?} {right:?} not implemented
- Metal strided unary {name} {dtype:?} not implemented
- unsupported const-set f8e4m3
- unsupported const-set f64
- Metal contiguous unary {name} {dtype:?} not implemented
AI-assisted analysis of huggingface/candle@d5fee525bf (2026-09-02).
Data as JSON: /api/errors/1c476b7edb92d869.
Report an issue: GitHub.