tracel-ai/burn · error
Can't convert a non leaf tensor into a tracked tensor
Error message
Can't convert a non leaf tensor into a tracked tensor
What it means
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.
Source
Thrown at crates/burn-autodiff/src/tensor.rs:110
primitive,
node: node.clone(),
}
}
pub fn is_tracked(&self) -> bool {
!self.node.requirement.is_none()
}
/// Mark the tensor as requiring gradients.
///
/// # Panics
///
/// It panics if the tensor is not a leaf.
pub fn require_grad(mut self) -> Self {
match self.node.requirement {
Requirement::Grad => self,
Requirement::GradInBackward => {
panic!("Can't convert a non leaf tensor into a tracked tensor")
}
Requirement::None => {
self.node = Node::new(
vec![],
0,
self.node.id,
Requirement::Grad,
self.node.properties.clone(),
self.node.client.clone(),
self.node.distributed_params.clone(),
)
.into();
let step = RootStep::new(self.node.clone());
self.register_step(step, CheckpointerBuilder::default())
}
}
}View on GitHub (pinned to d16f7ba2ed)
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
Example fix
// before let out = x.matmul(&w); out.require_grad(); // panic: non-leaf // after let out = x.detach().matmul(&w).detach().require_grad(); // or require_grad on leaf inputs only
Defensive patterns
Strategy: validation
Validate before calling
// Only call require_grad on leaf tensors
fn safe_require_grad<T: Backend, const D: usize>(t: AutodiffTensor<T, D>) -> AutodiffTensor<T, D> {
// if t is a result of arithmetic, detach first
t.require_grad() // callers must ensure t is a leaf
} Type guard
fn is_leaf<B: Backend, const D: usize>(t: &AutodiffTensor<B, D>) -> bool {
// leaves have no parents in the graph; track provenance instead of introspection:
// return true only for tensors you created via Tensor::from_* or Param
unimplemented!("track leaf provenance in your code, e.g. via newtype wrapper")
} Try / catch
// Rust panics are not catchable in the autodiff path; prevent instead:
// keep a Leaf wrapper type:
struct LeafTensor<B: Backend, const D: usize>(AutodiffTensor<B, D>);
impl<B: Backend, const D: usize> LeafTensor<B, D> {
fn require_grad(self) -> AutodiffTensor<B, D> { self.0.require_grad() }
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- Can't differentiate avg pool 2d backward.
- Can't differentiate max pool2d with indices backward.
- Can't differentiate adaptive avg pool2d backward.
- Can't differentiate adaptive avg pool3d backward.
- Can't differentiate interpolate backward.
AI-assisted analysis of tracel-ai/burn@d16f7ba2ed (2026-09-05).
Data as JSON: /api/errors/745587749477e02c.
Report an issue: GitHub.