tracel-ai/burn · error

Autodiff float tensor is on the wrong backend (expected {bac

Error message

Autodiff float tensor is on the wrong backend (expected {backend}).

What it means

The `@autodiff` arm of the unwrap macro first unwraps an Autodiff-wrapped tensor kind, then expects the inner tensor to match the concrete backend. If the inner primitive is from a different backend, it panics with 'Autodiff float tensor is on the wrong backend'.

Source

Thrown at crates/burn-dispatch/src/macros.rs:410

        $vec.into_iter()
            .map(|t| match t.kind {
                $crate::DispatchTensorKind::$Backend(inner) => inner.$kind(),
                #[allow(unreachable_patterns)]
                _ => panic!(
                    "Tensor is on the wrong backend (expected {}).",
                    stringify!($Backend)
                ),
            })
            .collect::<Vec<_>>()
    };

    // Autodiff-wrapped backend
    (@autodiff $Backend:ident, $vec:expr, $kind:ident) => {
        $vec.into_iter()
            .map(|t| match t.kind {
                $crate::DispatchTensorKind::Autodiff(inner) => match *inner {
                    $crate::DispatchTensorKind::$Backend(inner) => inner.$kind(),
                    _ => panic!(
                        "Autodiff float tensor is on the wrong backend (expected {}).",
                        stringify!($Backend)
                    ),
                },
                _ => panic!(
                    "Expected autodiff-wrapped float tensor for backend {}.",
                    stringify!($Backend)
                ),
            })
            .collect::<Vec<_>>()
    };
}

/// Match arm generator for `transaction_op`.
macro_rules! transaction_op_arms {
    ($tx:ident, $first:expr; $([$Backend:ident, $cfg:meta]),*) => {{
        match &$first.kind {
            // Autodiff arm first

View on GitHub (pinned to d16f7ba2ed)

Solutions

  1. Build all autodiff tensors from the same inner backend that Autodiff<B> wraps
  2. Recreate the tensor on the wrapped backend before passing it in
  3. Verify the generic B parameter of your Autodiff<B> backend matches the tensors you pass

Example fix

// before
let ad = AutodiffTensor::from(wgpu_tensor); // used inside Autodiff<Cpu> graph
// after
let ad = AutodiffTensor::from(cpu_tensor); // inner tensor matches Autodiff<Cpu>
Defensive patterns

Strategy: validation

Validate before calling

fn check_ad_backend<B: AutodiffBackend>(t: &burn::tensor::Tensor<B, D>) -> bool { B::InnerBackend::device(&t.device()).is_ok() } // ensure the tensor belongs to Autodiff<B>'s inner backend

Type guard

fn is_ad_of_b<B: Backend>(t: &AdBackend<B>::Tensor<D>) -> bool { true } // rely on Rust generics: AdBackend<B> tensors are typed, so wrong-backend tensors won't compile

Prevention

When it happens

Trigger: Passing an Autodiff tensor whose inner backend tensor is not of the expected backend kind into an unwrap that requires the concrete backend (e.g. an Autodiff<Wgpu> tensor supplied to a Cpu-targeted operation).

Common situations: Wrapping one backend in Autodiff but passing tensors built from another backend into the training graph; constructing an Autodiff tensor manually from the wrong primitives.

Related errors


AI-assisted analysis of tracel-ai/burn@d16f7ba2ed (2026-09-05). Data as JSON: /api/errors/df50eea58d863c86. Report an issue: GitHub.