{"record":{"id":"212b20217bd2c0e2","repo":"tracel-ai/burn","slug":"cannot-move-a-tensor-from-a-capture-device","errorCode":null,"errorMessage":"Cannot move a tensor from a capture device","messagePattern":"Cannot move a tensor from a capture device","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/burn-dispatch/src/macros.rs","lineNumber":235,"sourceCode":"                                $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,\n            $tensor,\n            $device,\n            $to_device,\n            |$inner, $device_ident| $body\n        )","sourceCodeStart":217,"sourceCodeEnd":253,"githubUrl":"https://github.com/tracel-ai/burn/blob/d16f7ba2ed0d41408189384044cc886fb4c8f957/crates/burn-dispatch/src/macros.rs#L217-L253","documentation":"Capture tensors are placeholders recorded during graph/program capture (the `capture` feature); they never hold materialized device data. Attempting to move such a tensor OFF a capture device is intentionally forbidden — the comment in the source notes capture is one-way: initialized values may be moved onto a capture device, but captured tensors cannot be moved back because there is no underlying data.","triggerScenarios":"Invoking a to-device / cross-device move (macros.rs:235 arm) where the source tensor's DispatchTensorKind is Capture(_) — e.g. taking a tensor produced during capture and calling `to_device(other_device)` on it.","commonSituations":"Post-capture replay code accidentally treating captured placeholders as real tensors; exporting or checkpointing parts of a captured graph by moving tensors to a live device; mixing capture-mode and execution-mode code paths in the same session.","solutions":["Do not move capture-kind tensors off the capture device; materialize them by executing/replaying the captured graph first, then move the resulting real tensor.","Restructure code so device transfers happen before capture begins or after replay completes.","Guard transfers with a kind check and skip or re-record capture tensors instead of moving them.","If the data exists elsewhere, reference the original initialized tensor rather than its captured placeholder."],"exampleFix":"// before\ncaptured_tensor.to_device(&gpu_device); // Capture kind -> panic\n\n// after\nlet real = replay(captured_graph); // materialize data first\nreal.to_device(&gpu_device);","handlingStrategy":"type-guard","validationCode":"fn can_move(t: &DispatchPrimitive) -> bool {\n    !matches!(t.kind, DispatchTensorKind::Capture(_))\n}","typeGuard":"fn is_capture(t: &DispatchPrimitive) -> bool {\n    matches!(t.kind, DispatchTensorKind::Capture(_))\n}","tryCatchPattern":null,"preventionTips":["Filter out capture-kind tensors before any to_device loop.","Materialize captured graphs via replay before transferring results.","Keep capture-mode and execution-mode code paths clearly separated."],"tags":["rust","capture","tensor","device-transfer","burn"],"backgroundTag":"capture-tensor-not-materialized","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"}