tracel-ai/burn · error

Backend not supported for custom op `{}`

Error message

Backend not supported for custom op `{}`

What it means

The burn-backend-extension codegen's gen_tensor_input_dispatch_body (crates/burn-backend-extension/src/extension.rs:497) generates a match over backend tags for a custom op; if the runtime backend tag does not match any generated dispatch arm, the generated code calls unimplemented!("Backend not supported for custom op `{}`"). This means the custom op was declared without support for the backend actually being used.

Source

Thrown at crates/burn-backend-extension/src/extension.rs:497

            bool,
        ) = {
            #routing_tensor_init
            #autodiff_context
            let __backend_tag = match &__routing_tensor.kind {
                #ad_tag_arm
                #( #concrete_tag_arms )*
                #[allow(unreachable_patterns)]
                _ => usize::MAX,
            };
            (
                __backend_tag,
                __ad_ctx,
                __routing_tensor_is_float,
            )
        };
        match (__burn_backend_tag, __has_float_input) {
            #( #dispatch_arms )*
            _ => unimplemented!("Backend not supported for custom op `{}`", stringify!(#name)),
        }
    }
}

/// Generate all context routes for one selected concrete backend.
fn gen_tensor_input_backend_arm(
    ir: &Extension,
    op: &Operation,
    backend: &Backend,
    i: usize,
    ad_cfg_attr: &Option<TokenStream2>,
) -> TokenStream2 {
    let cfg_attr = backend.cfg_attr.clone();
    let routes = routing::extension_backend_routes(
        op,
        &backend.ident,
        ir.backends.autodiff.0,
        ad_cfg_attr.as_ref(),

View on GitHub (pinned to d16f7ba2ed)

Solutions

  1. Add the missing backend to the custom op's declaration (its backend list / feature gates) so a dispatch arm is generated.
  2. Enable the corresponding crate feature so the backend arm is compiled in.
  3. Route the call to a backend that the op supports.

Example fix

// before
#[extension(op)]
#[.backends(wgpu)]
fn my_op(x: Tensor) -> Tensor { ... }
// run with NdArray -> panic
// after
#[extension(op)]
#[.backends(wgpu, ndarray)]
fn my_op(x: Tensor) -> Tensor { ... }
Defensive patterns

Strategy: validation

Validate before calling

// compile-time: list every backend you run with in the op declaration
#[.backends(wgpu, ndarray)] // ensure all target backends are declared

Prevention

When it happens

Trigger: Invoking a custom op (via #[burn_extension]) with a backend that was not enabled/declared in the op's backend list, so no dispatch arm matches and the fallback arm panics.

Common situations: Declaring a custom op only for wgpu/cubecl backends and then running it with ndarray (CPU), or enabling a backend feature after op registration without re-declaring backend support.

Related errors


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