{"record":{"id":"60db1da2885d2394","repo":"tracel-ai/burn","slug":"autodiff-should-not-wrap-an-autodiff-device","errorCode":null,"errorMessage":"Autodiff should not wrap an autodiff device.","messagePattern":"Autodiff should not wrap an autodiff device\\.","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/burn-backend-extension/src/dispatch.rs","lineNumber":342,"sourceCode":"fn expand_creation(\n    device: &syn::Ident,\n    output: &OperationOutput,\n    body: &syn::Block,\n) -> TokenStream {\n    let direct_arms = BACKENDS\n        .iter()\n        .map(|backend| creation_arm(backend, output, body, false));\n    let autodiff_arms = BACKENDS\n        .iter()\n        .map(|backend| creation_arm(backend, output, body, true));\n    quote! {\n        match #device {\n            #(#direct_arms)*\n            #[cfg(feature = \"autodiff\")]\n            crate::DispatchDevice::Autodiff(__device) => match __device.inner.as_ref() {\n                #(#autodiff_arms)*\n                crate::DispatchDevice::Autodiff(_) => {\n                    panic!(\"Autodiff should not wrap an autodiff device.\")\n                }\n                #[allow(unreachable_patterns)]\n                __other => panic!(\"unsupported dispatch device: {__other:?}\"),\n            },\n            #[allow(unreachable_patterns)]\n            __other => panic!(\"unsupported dispatch device: {__other:?}\"),\n        }\n    }\n}\n\nfn creation_arm(\n    backend: &crate::BackendSpec,\n    output: &OperationOutput,\n    body: &syn::Block,\n    autodiff_device: bool,\n) -> TokenStream {\n    let ident = syn::Ident::new(backend.name, proc_macro2::Span::call_site());\n    let cfg: TokenStream = backend.cfg.parse().expect(\"valid backend cfg\");","sourceCodeStart":324,"sourceCodeEnd":360,"githubUrl":"https://github.com/tracel-ai/burn/blob/d16f7ba2ed0d41408189384044cc886fb4c8f957/crates/burn-backend-extension/src/dispatch.rs#L324-L360","documentation":"This panic is generated by the backend-dispatch proc macro in expand_creation. It fires when a DispatchDevice::Autodiff device's inner device is itself an Autodiff variant, i.e. a doubly-nested autodiff device. The macro assumes autodiff wraps exactly one concrete backend, so double wrapping is an unrecoverable invariant violation.","triggerScenarios":"Constructing or creating a tensor/operation with DispatchDevice::Autodiff whose inner .inner is DispatchDevice::Autodiff(_) — e.g. wrapping an already-wrapped autodiff device when building the dispatch device.","commonSituations":"Hand-constructing a DispatchDevice instead of using the provided constructors; migrating code across versions where the wrapper API changed; double-applying an autodiff adapter around a backend device.","solutions":["Do not wrap an autodiff device again; pass the concrete inner backend device to the Autodiff constructor","Unwrap once: build Autodiff from the plain backend device (e.g. the Cpu/Wgpu/Cube device), not from another Autodiff device","Check the code path that produced the device and remove the redundant wrapping layer"],"exampleFix":"// before\nlet device = DispatchDevice::Autodiff(AutodiffDevice::new(DispatchDevice::Autodiff(inner)));\n// after\nlet device = DispatchDevice::Autodiff(AutodiffDevice::new(inner));","handlingStrategy":"validation","validationCode":"fn ensure_not_double_autodiff(device: &DispatchDevice) -> Result<(), String> {\n    if let DispatchDevice::Autodiff(inner) = device {\n        if matches!(inner.inner.as_ref(), DispatchDevice::Autodiff(_)) {\n            return Err(\"Autodiff device must not wrap another Autodiff device\".into());\n        }\n    }\n    Ok(())\n}","typeGuard":"fn is_concrete_device(d: &DispatchDevice) -> bool {\n    !matches!(d, DispatchDevice::Autodiff(_))\n}","tryCatchPattern":null,"preventionTips":["Always build Autodiff devices from a concrete backend device via the library constructors","Add an assertion/debug check that unwrap-inner of Autodiff is concrete","Centralize device construction in one helper to avoid accidental double wrapping"],"tags":["rust","proc-macro","autodiff","device-dispatch"],"backgroundTag":"autodiff-device-double-wrap","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"}