{"record":{"id":"081b1270840ffdd4","repo":"tracel-ai/burn","slug":"operation-not-marked-for-autodiff","errorCode":null,"errorMessage":"Operation not marked for autodiff.","messagePattern":"Operation not marked for autodiff\\.","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/burn-dispatch/src/macros.rs","lineNumber":230,"sourceCode":"                        type B2 = $crate::backends::$B2;\n                        let $inner = tensor.$inner_fn();\n\n                        $crate::DispatchTensor {\n                            kind: $crate::DispatchTensorKind::$B2(\n                                $crate::BackendTensor::$kind($body)\n                            ),\n                            autodiff: $crate::DispatchAutodiffContext::Enabled(\n                                device_ad.checkpointing,\n                            ),\n                        }\n\n                    },\n                )+\n            )*\n            #[cfg(feature = \"autodiff\")]\n            (_, $crate::DispatchDevice::Autodiff(_)) => unreachable!(\"Autodiff should not wrap an autodiff device.\"),\n            #[cfg(feature = \"autodiff\")]\n            ($crate::DispatchTensorKind::Autodiff(..), _) => panic!(\"Operation not marked for autodiff.\"),\n            // Capture is intentionally one-way: initialized values can be moved onto a\n            // capture device, but captured tensors have no materialized data to move back.\n            #[cfg(feature = \"capture\")]\n            ($crate::DispatchTensorKind::Capture(_), _) => {\n                panic!(\"Cannot move a tensor from a capture device\")\n            }\n        }\n    };\n}\n\n/// Handles tensor movement between devices, supporting both same-backend transfers\n/// and cross-backend dispatches.\nmacro_rules! to_device {\n    ($kind:ident, $inner_fn:ident, $tensor:expr, $device:expr, $to_device:ident, |$inner:ident, $device_ident:ident| $body:expr) => {\n        backend_matrix!(\n            to_device_arms,\n            $kind,\n            $inner_fn,","sourceCodeStart":212,"sourceCodeEnd":248,"githubUrl":"https://github.com/tracel-ai/burn/blob/d16f7ba2ed0d41408189384044cc886fb4c8f957/crates/burn-dispatch/src/macros.rs#L212-L248","documentation":"A tensor whose DispatchTensorKind is Autodiff was passed to a device-movement/matching path without a corresponding autodiff arm enabled — the macro's autodiff-kind catch-all panics 'Operation not marked for autodiff.' This means the operation or macro invocation was generated without the autodiff marker even though the tensor carries autodiff state, so the dispatcher cannot know how to propagate gradients or move the tensor correctly.","triggerScenarios":"Calling a backend operation on an Autodiff-kind tensor while the operation was not registered/generated with the autodiff arm (the `#[cfg(feature = \"autodiff\")]` kind arm at macros.rs:230 fires when the operation/tensor-kind pair has no marked match arm) — e.g. using a raw backend tensor op inside an Autodiff context, or a custom op not wrapped with burn_autodiff's registration macros.","commonSituations":"Implementing custom autodiff ops without `#[derive]`/macro registration; calling lower-level backend APIs directly with dispatch tensors; mixing non-autodiff operation macro instances with autodiff tensors after toggling the autodiff feature.","solutions":["Register the operation for autodiff using burn_autodiff's operation macros (e.g. `use burn_autodiff::ops::*` and the corresponding backward-op registration) so an autodiff arm is generated.","If the op should not differentiate, convert the tensor to a non-autodiff kind (detach via `.inner()` / backend tensor) before the call.","Ensure the `autodiff` feature is enabled consistently across all crates in the workspace so generated arms match.","Wrap the call in the dispatch macro variant intended for autodiff (marked arms), not the plain backend variant."],"exampleFix":"// before\ntensor.dispatch(op) // Autodiff-kind tensor, op has no autodiff arm -> panic\n\n// after\nuse burn_autodiff::ops::register_op;\nregister_op!(MyOp); // generates the autodiff arm\ntensor.dispatch(MyOp)","handlingStrategy":"type-guard","validationCode":"fn ensure_marked_for_autodiff(kind: &DispatchTensorKind) {\n    if matches!(kind, DispatchTensorKind::Autodiff(_)) {\n        assert!(op_registered_for_autodiff(), \"op must use burn_autodiff::ops registration\");\n    }\n}","typeGuard":"fn is_autodiff_tensor(t: &DispatchPrimitive) -> bool {\n    matches!(t.kind, DispatchTensorKind::Autodiff(_))\n}","tryCatchPattern":null,"preventionTips":["Register every custom op with burn_autodiff's ops macros before using autodiff tensors with it.","Detach (`.inner()`) tensors that should not participate in gradient tracking.","Keep the `autodiff` feature uniform across workspace crates."],"tags":["rust","autodiff","macro","tensor","burn"],"backgroundTag":"operation-not-marked-for-autodiff","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"}