{"record":{"id":"745587749477e02c","repo":"tracel-ai/burn","slug":"can-t-convert-a-non-leaf-tensor-into-a-tracked-ten","errorCode":null,"errorMessage":"Can't convert a non leaf tensor into a tracked tensor","messagePattern":"Can't convert a non leaf tensor into a tracked tensor","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/burn-autodiff/src/tensor.rs","lineNumber":110,"sourceCode":"            primitive,\n            node: node.clone(),\n        }\n    }\n\n    pub fn is_tracked(&self) -> bool {\n        !self.node.requirement.is_none()\n    }\n\n    /// Mark the tensor as requiring gradients.\n    ///\n    /// # Panics\n    ///\n    /// It panics if the tensor is not a leaf.\n    pub fn require_grad(mut self) -> Self {\n        match self.node.requirement {\n            Requirement::Grad => self,\n            Requirement::GradInBackward => {\n                panic!(\"Can't convert a non leaf tensor into a tracked tensor\")\n            }\n            Requirement::None => {\n                self.node = Node::new(\n                    vec![],\n                    0,\n                    self.node.id,\n                    Requirement::Grad,\n                    self.node.properties.clone(),\n                    self.node.client.clone(),\n                    self.node.distributed_params.clone(),\n                )\n                .into();\n                let step = RootStep::new(self.node.clone());\n\n                self.register_step(step, CheckpointerBuilder::default())\n            }\n        }\n    }","sourceCodeStart":92,"sourceCodeEnd":128,"githubUrl":"https://github.com/tracel-ai/burn/blob/d16f7ba2ed0d41408189384044cc886fb4c8f957/crates/burn-autodiff/src/tensor.rs#L92-L128","documentation":"require_grad can only be called on a leaf tensor (one whose gradient requirement is Grad or None). If the tensor is an intermediate result (Requirement::GradInBackward), it is not a leaf and converting it to a tracked tensor would corrupt the autodiff graph, so the library panics.","triggerScenarios":"Calling x.require_grad() on the output of another operation (a matmul/conv result) rather than on a freshly created tensor; chaining require_grad after arithmetic in training loops where the intent was to accumulate grads mid-graph.","commonSituations":"Freezing/unfreezing weights but calling require_grad on cached intermediate tensors; migrating PyTorch .requires_grad_() semantics (which applies to any tensor) to burn where it is leaf-only; hand-written training loops manipulating grad requirements mid-step.","solutions":["Only call require_grad on leaf tensors created via Tensor::from_* constructors or as module parameters","Detach the intermediate first if you truly need a new tracked root: t.detach().require_grad()","Restructure so gradient requirement is set once at tensor creation, not mid-graph","Keep tensors you intend to toggle as Parameters of a module and toggle the module's grad setting"],"exampleFix":"// before\nlet out = x.matmul(&w);\nout.require_grad(); // panic: non-leaf\n// after\nlet out = x.detach().matmul(&w).detach().require_grad(); // or require_grad on leaf inputs only","handlingStrategy":"validation","validationCode":"// Only call require_grad on leaf tensors\nfn safe_require_grad<T: Backend, const D: usize>(t: AutodiffTensor<T, D>) -> AutodiffTensor<T, D> {\n    // if t is a result of arithmetic, detach first\n    t.require_grad() // callers must ensure t is a leaf\n}","typeGuard":"fn is_leaf<B: Backend, const D: usize>(t: &AutodiffTensor<B, D>) -> bool {\n    // leaves have no parents in the graph; track provenance instead of introspection:\n    // return true only for tensors you created via Tensor::from_* or Param\n    unimplemented!(\"track leaf provenance in your code, e.g. via newtype wrapper\")\n}","tryCatchPattern":"// Rust panics are not catchable in the autodiff path; prevent instead:\n// keep a Leaf wrapper type:\nstruct LeafTensor<B: Backend, const D: usize>(AutodiffTensor<B, D>);\nimpl<B: Backend, const D: usize> LeafTensor<B, D> {\n    fn require_grad(self) -> AutodiffTensor<B, D> { self.0.require_grad() }\n}","preventionTips":["Call require_grad only on tensors you constructed, never on op outputs","Use .detach() before require_grad if a new tracked root is needed","Toggle grad via module Parameters rather than runtime tensors","Never replicate PyTorch's .requires_grad_() on intermediate tensors — burn is leaf-only"],"tags":["rust","autodiff","leaf-tensor","gradient-tracking"],"backgroundTag":"non-leaf-tensor-requires-grad","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"}