{"record":{"id":"24290de87af38d10","repo":"huggingface/candle","slug":"input-is-not-a-f32-tensor","errorCode":null,"errorMessage":"input is not a f32 tensor","messagePattern":"input is not a f32 tensor","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"candle-core/src/custom_op.rs","lineNumber":748,"sourceCode":"#[cfg(feature = \"ug\")]\nimpl InplaceOp1 for UgIOp1 {\n    fn name(&self) -> &'static str {\n        self.name\n    }\n\n    fn cpu_fwd(&self, _: &mut CpuStorage, _: &Layout) -> Result<()> {\n        crate::bail!(\"ug ops are only supported on metal/cuda at the moment\")\n    }\n\n    #[cfg(feature = \"metal\")]\n    fn metal_fwd(&self, sto: &mut MetalStorage, layout: &Layout) -> Result<()> {\n        use crate::backend::BackendStorage;\n        use objc2_metal;\n\n        let elem_count = layout.shape().elem_count();\n        if sto.dtype() != crate::DType::F32 {\n            // TODO: support more dtypes.\n            crate::bail!(\"input is not a f32 tensor\")\n        }\n        let device = sto.device();\n        let encoder = device.command_encoder()?;\n        encoder.set_compute_pipeline_state(&self.func);\n        candle_metal_kernels::debug_group!(encoder, \"{}\", self.name);\n        let (g, b) = if elem_count.is_multiple_of(32) {\n            (elem_count / 32, 32)\n        } else {\n            (elem_count, 1)\n        };\n        let grid_dims = objc2_metal::MTLSize {\n            width: g,\n            height: 1,\n            depth: 1,\n        };\n        let group_dims = candle_metal_kernels::utils::get_block_dims(b, 1, 1);\n        let encoder: &candle_metal_kernels::metal::ComputeCommandEncoder = encoder.as_ref();\n        encoder.set_output_buffer(0, Some(sto.buffer()), 0);","sourceCodeStart":730,"sourceCodeEnd":766,"githubUrl":"https://github.com/huggingface/candle/blob/d5fee525bfde3273eb7c9b75fd2bc4937be867ca/candle-core/src/custom_op.rs#L730-L766","documentation":"candle's metal_fwd custom op for Metal only supports F32 tensors. Before launching the Metal compute pipeline it checks the storage dtype and bails if it is not DType::F32. Only F32 is implemented so far (a TODO notes more dtypes are planned).","triggerScenarios":"Calling Tensor::apply_arisc or any custom op backed by MetalCustomOp when the input tensor storage has dtype other than F32 (e.g. BF16, F16, F64, I64, U8) on a Metal device.","commonSituations":"Running on Apple Silicon where candle selects the Metal backend; loading a model with bf16/f16 weights; creating tensors with Tensor::new on integer data and applying a custom op.","solutions":["Convert the tensor to F32 before applying the custom op: tensor.to_dtype(candle_core::DType::F32)?.","Ensure model weights are loaded/quantized as f32 when targeting Metal custom ops.","If you own the op, extend metal_fwd to support the needed dtype instead of relying on F32 only."],"exampleFix":"// before\nlet out = tensor.apply(&custom_op)?;\n// after\nlet out = tensor.to_dtype(DType::F32)?.apply(&custom_op)?;","handlingStrategy":"validation","validationCode":"if tensor.dtype() != candle_core::DType::F32 {\n    tensor = tensor.to_dtype(candle_core::DType::F32)?;\n}","typeGuard":"fn is_f32(t: &candle_core::Tensor) -> bool { t.dtype() == candle_core::DType::F32 }","tryCatchPattern":null,"preventionTips":["Normalize input tensors to F32 at pipeline entry on Metal devices.","Load weights as f32 when using Metal custom ops.","Check dtype with tensor.dtype() before any custom op."],"tags":["metal","dtype","gpu","custom-op"],"backgroundTag":"unsupported-tensor-dtype","analyzedSha":"d5fee525bfde3273eb7c9b75fd2bc4937be867ca","analyzedAt":"2026-09-02T00:15:47.023Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-09T06:17:21.866Z"}