{"record":{"id":"61b72d9411895507","repo":"tracel-ai/burn","slug":"an-enabled-float-tensor-must-use-an-autodiff-primi-61b72d","errorCode":null,"errorMessage":"an enabled float tensor must use an autodiff primitive","messagePattern":"an enabled float tensor must use an autodiff primitive","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/burn-dispatch/src/ops/qtensor.rs","lineNumber":302,"sourceCode":"            (TensorPrimitive::QFloat(lhs), TensorPrimitive::QFloat(rhs)) => {\n                let autodiff = lhs.autodiff.merge(rhs.autodiff);\n                // With no float input, the first tensor is the routing tensor.\n                backend_list!(q_matmul_qq_arms, lhs, rhs, autodiff)\n            }\n            (TensorPrimitive::Float(lhs), TensorPrimitive::QFloat(rhs)) => {\n                let autodiff = lhs.autodiff.merge(rhs.autodiff);\n                #[cfg(feature = \"autodiff\")]\n                match (\n                    matches!(&lhs.kind, DispatchTensorKind::Autodiff(_)),\n                    lhs.autodiff,\n                ) {\n                    (true, DispatchAutodiffContext::Enabled(_))\n                    | (false, DispatchAutodiffContext::Disabled) => {}\n                    (true, DispatchAutodiffContext::Disabled) => {\n                        panic!(\"an autodiff float primitive must have an enabled autodiff context\")\n                    }\n                    (false, DispatchAutodiffContext::Enabled(_)) => {\n                        panic!(\"an enabled float tensor must use an autodiff primitive\")\n                    }\n                }\n                backend_list!(q_matmul_fq_arms, lhs, rhs, autodiff)\n            }\n            (TensorPrimitive::QFloat(lhs), TensorPrimitive::Float(rhs)) => {\n                let autodiff = lhs.autodiff.merge(rhs.autodiff);\n                #[cfg(feature = \"autodiff\")]\n                match (\n                    matches!(&rhs.kind, DispatchTensorKind::Autodiff(_)),\n                    rhs.autodiff,\n                ) {\n                    (true, DispatchAutodiffContext::Enabled(_))\n                    | (false, DispatchAutodiffContext::Disabled) => {}\n                    (true, DispatchAutodiffContext::Disabled) => {\n                        panic!(\"an autodiff float primitive must have an enabled autodiff context\")\n                    }\n                    (false, DispatchAutodiffContext::Enabled(_)) => {\n                        panic!(\"an enabled float tensor must use an autodiff primitive\")","sourceCodeStart":284,"sourceCodeEnd":320,"githubUrl":"https://github.com/tracel-ai/burn/blob/d16f7ba2ed0d41408189384044cc886fb4c8f957/crates/burn-dispatch/src/ops/qtensor.rs#L284-L320","documentation":"This panic fires inside dispatch's q_matmul when one matmul operand is a Float tensor whose autodiff context is Enabled, but the tensor's backend primitive is not an autodiff primitive. Burn maintains an invariant pairing: a float tensor primitive that supports autodiff must always be accompanied by an enabled autodiff context (and vice versa). Mixing a plain float primitive with an enabled autodiff context means internal state got out of sync, so the library panics rather than silently skipping gradient tracking.","triggerScenarios":"Calling matmul between two quantized-float (QFloat) tensors or float/QFloat mixes where one TensorPrimitive::Float was built from a non-autodiff backend primitive while its `autodiff` field is DispatchAutodiffContext::Enabled — i.e., the Float tensor's `is_autodiff()`-style check (matches! on DispatchTensorKind::Autodiff) is false but `rhs.autodiff`/`lhs.autodiff` is Enabled.","commonSituations":"Constructing dispatch tensors manually with mismatched primitive/kind and autodiff context; wrapping a plain (non-autodiff) backend tensor in an Enabled autodiff context; bugs in custom backend adapters or capture/replay paths that rebuild TensorPrimitive::Float incorrectly.","solutions":["Ensure every Float tensor carrying DispatchAutodiffContext::Enabled is created from an autodiff backend primitive (DispatchTensorKind::Autodiff) so the kind and context agree.","If the tensor truly is a non-autodiff float primitive, construct it with DispatchAutodiffContext::Disabled.","When mixing operands, verify that merging autodiff contexts (lhs.autodiff.merge(rhs.autodiff)) matches the actual primitive kinds of both sides.","If this arises inside burn itself, report it — it indicates a broken invariant in the dispatch layer, not user error in a normal op call."],"exampleFix":"// before (mismatched: plain primitive + enabled context)\nlet t = BackendTensor::Float(float_primitive); // primitive kind: Float\nlet t = TensorPrimitive::Float { kind: DispatchTensorKind::Float(..), autodiff: DispatchAutodiffContext::Enabled(ctx) };\n// after (consistent)\nlet t = TensorPrimitive::Float { kind: DispatchTensorKind::Autodiff(autodiff_primitive), autodiff: DispatchAutodiffContext::Enabled(ctx) };","handlingStrategy":"validation","validationCode":"// before q_matmul on float operands\nfn ensure_ad_consistent(t: &TensorPrimitive<DispatchBackend>) -> Result<(), String> {\n    let is_ad = matches!(t.tensor().kind, DispatchTensorKind::Autodiff(_));\n    let ctx_enabled = matches!(&t.tensor().autodiff, DispatchAutodiffContext::Enabled(_));\n    if is_ad == ctx_enabled { Ok(()) } else { Err(format!(\"autodiff kind/context mismatch: kind_ad={is_ad}, ctx_enabled={ctx_enabled}\")) }\n}","typeGuard":"fn is_autodiff_float<B: Backend>(t: &BackendTensor<B>) -> bool {\n    matches!(t, BackendTensor::Autodiff(_))\n        || matches!(t, BackendTensor::Float(f) if matches!(f.kind, DispatchTensorKind::Autodiff(_)))\n}","tryCatchPattern":null,"preventionTips":["Always construct Float tensors through constructors that derive kind and autodiff context from the same primitive.","Never hand-set DispatchAutodiffContext::Enabled on a plain float primitive.","After merging autodiff contexts, re-check that the merged state matches the operand primitive kinds.","Add debug assertions for kind/context consistency in custom backend adapters."],"tags":["rust","autodiff","dispatch","tensor","panic"],"backgroundTag":"autodiff-primitive-context-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"}