{"record":{"id":"0ba6cd60c611f309","repo":"tracel-ai/burn","slug":"q-matmul-inputs-are-on-different-backends","errorCode":null,"errorMessage":"q_matmul inputs are on different backends","messagePattern":"q_matmul inputs are on different backends","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/burn-dispatch/src/ops/qtensor.rs","lineNumber":81,"sourceCode":"    }};\n}\n\nmacro_rules! q_matmul_qq_arms {\n    ($lhs:expr, $rhs:expr, $autodiff:expr; $([$Backend:ident, $cfg:meta]),*) => {{\n        match ($lhs.kind, $rhs.kind) {\n            $(\n                #[cfg($cfg)]\n                (DispatchTensorKind::$Backend(lhs), DispatchTensorKind::$Backend(rhs)) => {\n                    type B = crate::backends::$Backend;\n                    let output = B::q_matmul(\n                        TensorPrimitive::QFloat(lhs.quantized()),\n                        TensorPrimitive::QFloat(rhs.quantized()),\n                    );\n                    wrap_q_matmul_concrete!($Backend, output, $autodiff)\n                }\n            )*\n            #[allow(unreachable_patterns)]\n            _ => panic!(\"q_matmul inputs are on different backends\"),\n        }\n    }};\n}\n\nmacro_rules! q_matmul_fq_arms {\n    ($lhs:expr, $rhs:expr, $autodiff:expr; $([$Backend:ident, $cfg:meta]),*) => {{\n        match ($lhs.kind, $rhs.kind) {\n            $(\n                #[cfg($cfg)]\n                (DispatchTensorKind::$Backend(lhs), DispatchTensorKind::$Backend(rhs)) => {\n                    match $autodiff {\n                        DispatchAutodiffContext::Disabled => {\n                            type B = crate::backends::$Backend;\n                            let output = B::q_matmul(\n                                TensorPrimitive::Float(lhs.float()),\n                                TensorPrimitive::QFloat(rhs.quantized()),\n                            );\n                            wrap_q_matmul_concrete!($Backend, output, DispatchAutodiffContext::Disabled)","sourceCodeStart":63,"sourceCodeEnd":99,"githubUrl":"https://github.com/tracel-ai/burn/blob/d16f7ba2ed0d41408189384044cc886fb4c8f957/crates/burn-dispatch/src/ops/qtensor.rs#L63-L99","documentation":"This panic is the catch-all arm of the quantized-x-quantized q_matmul dispatch macro (q_matmul_qq_arms). The dispatcher holds each tensor tagged with its backend (DispatchTensorKind), and it only has compiled arms for both operands carrying the SAME backend. When lhs and rhs carry different backend tags the wildcard arm is reached and burn panics, because a backend-specific q_matmul kernel cannot operate across two different backends.","triggerScenarios":"Calling q_matmul (or Tensor::matmul on quantized tensors) where the two DispatchTensors have different DispatchTensorKind variants — e.g. a tensor created on the cubecl-wgpu backend multiplied against one on the tch/candle backend, or one operand silently falling through to a different backend via a conversion.","commonSituations":"Mixing tensors created by different Backend types in generic code; moving one tensor to a different device/backend and forgetting the other; combining a quantized checkpoint loaded under one backend with a runtime tensor under another; generic functions parameterized over two different backend type parameters.","solutions":["Ensure both quantized operands are created by (or moved to) the same backend before the matmul","Move one tensor to the other's backend/device using to_device / re-creation on the same backend","Audit generic code so both operands flow through the same Backend type parameter","Check that conversions (quantize/dequantize) did not swap the underlying backend of one operand"],"exampleFix":"// before\nlet a = QTensor::from_data(data_a, &wgpu_device); // wgpu backend\nlet b = QTensor::from_data(data_b, &tch_device);  // tch backend\nlet c = a.matmul(b); // panic: different backends\n// after\nlet b = QTensor::from_data(data_b, &wgpu_device); // same backend/device\nlet c = a.matmul(b);","handlingStrategy":"validation","validationCode":"fn same_backend_qq(lhs: &DispatchTensor, rhs: &DispatchTensor) -> bool {\n    core::mem::discriminant(&lhs.kind) == core::mem::discriminant(&rhs.kind)\n}\nassert!(same_backend_qq(&lhs, &rhs), \"operands must share a backend before q_matmul\");","typeGuard":"fn is_qfloat(t: &DispatchTensor) -> bool {\n    !matches!(t.kind, DispatchTensorKind::Autodiff(_)) && t.autodiff == DispatchAutodiffContext::Disabled\n}\nfn same_kind(a: &DispatchTensor, b: &DispatchTensor) -> bool {\n    core::mem::discriminant(&a.kind) == core::mem::discriminant(&b.kind)\n}","tryCatchPattern":null,"preventionTips":["Keep an entire model (weights + activations) on a single backend and device","In generic code, take one Backend type parameter and use it for every operand","After moving/quantizing a tensor, verify its backend tag before combining it","Write a small unit test that asserts both operands' DispatchTensorKind discriminants match"],"tags":["burn","backend-mismatch","quantization","panic"],"backgroundTag":"tensor-backend-mismatch","analyzedSha":"d16f7ba2ed0d41408189384044cc886fb4c8f957","analyzedAt":"2026-09-05T13:19:14.260Z","contentChangedAt":"2026-09-05T13:19:14.260Z","schemaVersion":2},"datasetVersion":"2026-09-12T17:17:11.597Z"}