tracel-ai/burn · error
an enabled float tensor must use an autodiff primitive
Error message
an enabled float tensor must use an autodiff primitive
What it means
Generated by extract_selected_input for float tensor inputs routed to a non-autodiff primitive: the macro requires DispatchAutodiffContext::Disabled. If the context is Enabled (the tensor carries autodiff state), the operation panics because an enabled float tensor must go through the autodiff primitive, not the concrete one.
Source
Thrown at crates/burn-backend-extension/src/routing.rs:541
let name = &input.name;
let selected = format_ident!("__burn_selected");
let dispatch_root = &extraction.paths.dispatch_root;
let backend_alias = &extraction.paths.backend_alias;
let context = quote!(#dispatch_root::DispatchAutodiffContext);
assert!(
kind == TensorKind::Float || !autodiff_variant,
"only a float input can directly select an autodiff primitive"
);
let validate_context = if kind == TensorKind::Float && autodiff_variant {
quote! {
let #context::Enabled(_) = __burn_selected_context else {
panic!("an autodiff float primitive must have an enabled autodiff context")
};
}
} else if kind == TensorKind::Float {
quote! {
let #context::Disabled = __burn_selected_context else {
panic!("an enabled float tensor must use an autodiff primitive")
};
}
} else {
TokenStream::new()
};
if kind == TensorKind::Float && extraction.autodiff && !autodiff_variant {
let autodiff_trait = &extraction.paths.autodiff_trait;
if borrowed {
let lifted = format_ident!("__lifted_{name}");
quote! {
#validate_context
let #lifted = <#backend_alias as #autodiff_trait>::from_inner(#selected.as_float().clone());
let #name = &#lifted;
}
} else {
quote! {
#validate_contextView on GitHub (pinned to d16f7ba2ed)
Solutions
- Detach/stop tracking gradients on the tensor (e.g. .detach()) before passing it to the concrete dispatch path
- Or route through the autodiff-enabled operation variant instead
- Keep Enabled/Disabled tensor contexts consistent per operation call
Example fix
// before let out = op(tensor.require_grad()); // Enabled context into concrete path // after let out = op(tensor.detach()); // Disabled context for concrete dispatch
Defensive patterns
Strategy: type-guard
Validate before calling
fn require_disabled_context(t: &DispatchTensor) -> Result<(), String> {
match t.autodiff {
DispatchAutodiffContext::Disabled => Ok(()),
_ => Err("enabled float tensor must use the autodiff primitive; detach first".into()),
}
} Type guard
fn is_grad_disabled(t: &DispatchTensor) -> bool {
matches!(t.autodiff, DispatchAutodiffContext::Disabled)
} Try / catch
let out = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| op(&tensor)))
.map_err(|_| "tensor has gradient tracking; call .detach() or use the autodiff variant".to_string())? Prevention
- Call .detach() on training tensors before inference-only dispatch calls
- Separate training and inference code paths explicitly
- Never mix Enabled and Disabled tensors in one operation
When it happens
Trigger: Calling an operation whose selected float input resolves to the concrete backend primitive while the tensor's autodiff context is Enabled — e.g. passing a require_grad()/autodiff-wrapped tensor into a path compiled for the plain backend.
Common situations: Passing gradient-tracking tensors into inference-only ops; mixing autodiff-enabled and disabled tensors in one dispatch call; toggling require_grad on a tensor then routing it through a concrete-backend extension.
Related errors
- an autodiff float primitive must have an enabled autodiff co
- Autodiff should not wrap an autodiff device.
- Can't differentiate avg pool 2d backward.
- Can't differentiate max pool2d with indices backward.
- Can't differentiate adaptive avg pool2d backward.
AI-assisted analysis of tracel-ai/burn@d16f7ba2ed (2026-09-05).
Data as JSON: /api/errors/b710f2b327d4be92.
Report an issue: GitHub.