tracel-ai/burn · error
Unexpected Autodiff variant provided to `from_backend`
Error message
Unexpected Autodiff variant provided to `from_backend`
What it means
The `from_backend` macro-generated constructor re-tags each `BackendTensor` variant into a backend-specific `DispatchTensorKind`. The `Autodiff` variant has no valid target in this conversion, so encountering one is an internal misuse and the code panics with 'Unexpected Autodiff variant provided to `from_backend`'.
Source
Thrown at crates/burn-dispatch/src/tensor.rs:568
let kind = match tensor {
// Inverse: Wrap the `Float` variant back into the backend's `Autodiff` primitive variant
BackendTensor::Float(t) => {
let ad_tensor = BackendTensor::Autodiff(t);
// Wrap in the concrete backend's dispatch container
let inner_dispatch = DispatchTensorKind::$backend(ad_tensor);
// Re-apply the outer Autodiff dispatch wrapper
DispatchTensorKind::Autodiff(Box::new(inner_dispatch))
}
// Pass-throughs for non-differentiable types
BackendTensor::Int(t) => DispatchTensorKind::$backend(BackendTensor::Int(t)),
BackendTensor::Bool(t) => DispatchTensorKind::$backend(BackendTensor::Bool(t)),
BackendTensor::Quantized(t) => {
DispatchTensorKind::$backend(BackendTensor::Quantized(t))
}
BackendTensor::Autodiff(_) => {
panic!("Unexpected Autodiff variant provided to `from_backend`",)
}
};
DispatchTensor {
kind,
autodiff: DispatchAutodiffContext::Enabled(C::STRATEGY),
}
}
}
};
}
// One invocation per dispatch variant. Every cubecl runtime is the same `Cube`
// backend, so they share the one impl rather than getting seven identical ones.
impl_dispatch_conversion!(Cube, cube_backend);
impl_dispatch_conversion!(Flex, any(feature = "flex", default_backend));
impl_dispatch_conversion!(Remote, feature = "remote");
impl_dispatch_conversion!(Capture, feature = "capture");View on GitHub (pinned to d16f7ba2ed)
Solutions
- Strip the autodiff wrapper (extract the inner backend tensor) before calling `from_backend`.
- Use the autodiff-specific constructor/path that accepts `BackendTensor::Autodiff`.
- Add an upstream variant check and route autodiff tensors to the correct conversion.
Example fix
// before
let dt = DispatchTensor::from_backend(backend_tensor); // Autodiff variant panics
// after
let dt = match backend_tensor {
BackendTensor::Autodiff(t) => DispatchTensor::from_backend(BackendTensor::Float(t.inner())),
other => DispatchTensor::from_backend(other),
}; Defensive patterns
Strategy: validation
Validate before calling
if matches!(backend_tensor, BackendTensor::Autodiff(_)) { /* strip wrapper or use autodiff path */ } Type guard
fn is_plain_backend_tensor<B: Backend>(t: &BackendTensor<B>) -> bool {
!matches!(t, BackendTensor::Autodiff(_))
} Try / catch
let result = std::panic::catch_unwind(AssertUnwindSafe(|| DispatchTensor::from_backend(bt.clone())));
match result {
Ok(dt) => use_tensor(dt),
Err(_) => eprintln!("autodiff variant passed to non-autodiff constructor"),
} Prevention
- Strip the Autodiff wrapper before calling macro-generated from_backend constructors.
- Route autodiff tensors through autodiff-specific construction paths.
- Centralize BackendTensor -> DispatchTensor conversion in one checked helper.
When it happens
Trigger: Passing a `BackendTensor::Autodiff(_)` into the `from_backend` constructor for a concrete (non-autodiff) backend context — i.e. feeding an autodiff-wrapped tensor into a path that expects plain backend primitives.
Common situations: Custom backend or dispatch glue that forwards tensors without stripping the autodiff wrapper, or calling a non-autodiff constructor from autodiff-enabled code.
Related errors
- Requires autodiff tensor.
- an enabled float tensor must use an autodiff primitive
- Should be float, got autodiff
- Should be bool, got autodiff
- an autodiff float primitive must have an enabled autodiff co
AI-assisted analysis of tracel-ai/burn@d16f7ba2ed (2026-09-05).
Data as JSON: /api/errors/4bc0695e1dd11113.
Report an issue: GitHub.