{"record":{"id":"25a6d9f92ba14569","repo":"huggingface/candle","slug":"metal-contiguous-to-dtype-left-right-not-i","errorCode":null,"errorMessage":"Metal contiguous to_dtype {left:?} {right:?} not implemented","messagePattern":"Metal contiguous to_dtype (.+?) (.+?) not implemented","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"candle-core/src/metal_backend/mod.rs","lineNumber":597,"sourceCode":"                (DType::I64, DType::F16) => \"cast_i64_f16\",\n                (DType::I64, DType::F32) => \"cast_i64_f32\",\n                (DType::I64, DType::U32) => \"cast_i64_u32\",\n                (DType::I64, DType::U8) => \"cast_i64_u8\",\n\n                (DType::F16, DType::BF16) => \"cast_f16_bf16\",\n                (DType::F16, DType::F32) => \"cast_f16_f32\",\n                (DType::F16, DType::I64) => \"cast_f16_i64\",\n                (DType::F16, DType::U32) => \"cast_f16_u32\",\n                (DType::F16, DType::U8) => \"cast_f16_u8\",\n\n                (DType::BF16, DType::F16) => \"cast_bf16_f16\",\n                (DType::BF16, DType::F32) => \"cast_bf16_f32\",\n                (DType::BF16, DType::I64) => \"cast_bf16_i64\",\n                (DType::BF16, DType::U32) => \"cast_bf16_u32\",\n                (DType::BF16, DType::U8) => \"cast_bf16_u8\",\n\n                (left, right) => {\n                    crate::bail!(\"Metal contiguous to_dtype {left:?} {right:?} not implemented\")\n                }\n            };\n            candle_metal_kernels::call_cast_contiguous(\n                &device.device,\n                &encoder,\n                &device.kernels,\n                kernel_name,\n                self.dtype.size_in_bytes(),\n                el_count,\n                src,\n                &buffer,\n            )\n            .map_err(MetalError::from)?;\n        } else {\n            let kernel_name = match (self.dtype, dtype) {\n                (DType::BF16, DType::F16) => \"cast_bf16_f16_strided\",\n                (DType::BF16, DType::F32) => \"cast_bf16_f32_strided\",\n                (DType::BF16, DType::I64) => \"cast_bf16_i64_strided\",","sourceCodeStart":579,"sourceCodeEnd":615,"githubUrl":"https://github.com/huggingface/candle/blob/d5fee525bfde3273eb7c9b75fd2bc4937be867ca/candle-core/src/metal_backend/mod.rs#L579-L615","documentation":"candle's Metal backend only implements a fixed table of dtype-pair casts for contiguous to_dtype operations; any (from,to) pair outside the table hits the catch-all bail arm. This means the requested dtype conversion has no Metal kernel available, so the library refuses rather than silently falling back. It is a backend-coverage limitation, not user data corruption.","triggerScenarios":"Calling Tensor::to_dtype (or an op that casts internally) on a Metal device with a dtype pair not in the cast table, e.g. converting I64->F16, F32->I64 via the contiguous path, or any cast involving F64-style dtypes.","commonSituations":"Loading model weights stored in one dtype (e.g. i64 token ids) and casting to half precision for GPU inference; mixed-precision training pipelines converting between bf16 and integer types; dtype conversions that work on CPU but not on Metal.","solutions":["Cast on CPU first (tensor.to_device(&Device::Cpu)?.to_dtype(dtype)? then move back to Metal)","Use a supported dtype pair from the cast table (F32/F16/BF16/U8/U32/I64 combos that are listed)","Convert the tensor to F32 first, then to the target dtype, if both legs are supported","Run the workload on the CUDA or CPU backend which has broader cast coverage"],"exampleFix":"// before\nlet t = tensor.to_device(&metal_dev)?.to_dtype(DType::I64)?;\n// after\nlet t = tensor.to_dtype(DType::I64)?; // CPU-side cast, then .to_device(&metal_dev)","handlingStrategy":"validation","validationCode":"fn metal_cast_supported(from: candle_core::DType, to: candle_core::DType) -> bool {\n    use candle_core::DType::*;\n    matches!(\n        (from, to),\n        (F32, F16) | (F32, BF16) | (F32, I64) | (F32, U32) | (F32, U8)\n            | (F16, F32) | (BF16, F32) | (F16, BF16) | (BF16, F16)\n        // extend with the pairs your candle version's table lists\n    )\n}\nif !metal_cast_supported(t.dtype(), target) { t = t.to_device(&Device::Cpu)?.to_dtype(target)?.to_device(&metal_dev)?; }","typeGuard":null,"tryCatchPattern":"match tensor.to_dtype(target) {\n    Ok(t) => t,\n    Err(e) if e.to_string().contains(\"to_dtype\") && e.to_string().contains(\"not implemented\") => {\n        tensor.to_device(&Device::Cpu)?.to_dtype(target)?.to_device(&metal_dev)?\n    }\n    Err(e) => return Err(e.into()),\n}","preventionTips":["Keep model activations in F32/F16/BF16 on Metal","Do integer casts on CPU before moving to GPU","Pin a candle version and verify its Metal kernel coverage for your dtype mix"],"tags":["metal","gpu","dtype-cast","candle"],"backgroundTag":"unsupported-dtype-cast","analyzedSha":"d5fee525bfde3273eb7c9b75fd2bc4937be867ca","analyzedAt":"2026-09-02T00:15:47.023Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-09T06:17:21.866Z"}