tracel-ai/burn · error · syn::Error

Generic type `{ident}` should not be used on both a module f

Error message

Generic type `{ident}` should not be used on both a module field and a skipped field. Consider removing `#[module(skip)]` or using a different type for one of the fields.

What it means

burn-derive's #[Module] macro rejects a struct whose generics are used both on a module field (a field that generates module code) and on a field marked #[module(skip)]. Skipped fields are excluded from codegen, so if the same generic type parameter appears in both, the generated code would be inconsistent (the generic would be required for the skipped field but not tracked as a module parameter), so the proc macro fails at compile time pointing at the generic parameter.

Source

Thrown at crates/burn-derive/src/module/codegen_struct.rs:349

                let field_type = parse_module_field_type(field, generics)?;
                if field_type.is_module {
                    module_generics.extend(field_type.generic_idents.iter().cloned());
                } else if matches!(field_type.attr, Some(ModuleFieldAttribute::Skip)) {
                    skip_generics.extend(field_type.generic_idents.iter().cloned());
                }
                fields.push(ModuleField::new(field.clone(), field_type));
            }
        }
        syn::Data::Enum(_) => panic!("Only struct can be derived"),
        syn::Data::Union(_) => panic!("Only struct can be derived"),
    };

    for ident in module_generics.intersection(&skip_generics) {
        if let Some(param) = ast.generics.params.iter().find_map(|p| match p {
            syn::GenericParam::Type(tp) if tp.ident == *ident => Some(tp),
            _ => None,
        }) {
            return Err(syn::Error::new(
                param.ident.span(),
                format!(
                    "Generic type `{ident}` should not be used on both a module field and a skipped field. \
                     Consider removing `#[module(skip)]` or using a different type for one of the fields.",
                ),
            ));
        }
    }

    Ok(fields)
}

pub(crate) fn parse_module_field_type(
    field: &Field,
    generics: &mut ModuleGenerics,
) -> syn::Result<ModuleFieldType> {
    let mut field_type = ModuleFieldType::default();

View on GitHub (pinned to d16f7ba2ed)

Solutions

  1. Remove `#[module(skip)]` from the offending field so it participates in module codegen like the other field using the generic.
  2. Change the skipped field to a different (concrete or distinct generic) type so the two fields do not share the same generic parameter.
  3. Make the skipped field generic over a different type parameter (add a new generic) or hardcode its type.
  4. Store the skipped data outside the Module struct (e.g. in a wrapper struct holding the Module plus the extra field).

Example fix

// before
#[derive(Module)]
struct Net<B: Backend> {
    inner: Linear<B>,
    #[module(skip)]
    aux: Aux<B>, // same generic on skipped field: compile error
}
// after
#[derive(Module)]
struct Net<B: Backend> {
    inner: Linear<B>,
    #[module(skip)]
    aux: Aux<f32>, // or drop #[module(skip)] from aux
}
Defensive patterns

Strategy: validation

Validate before calling

// Compile-time: audit #[derive(Module)] structs so no generic ident appears
// both on a normal module field and on a #[module(skip)] field.
// e.g. `cargo check` fails at the generic param span; fix before building.

Prevention

When it happens

Trigger: Compiling a #[derive(Module)] struct where one type generic parameter appears on a regular module field (e.g. `inner: Linear<B>`) and also on a `#[module(skip)]` field (e.g. `#[module(skip)] extra: Option<T>`) with the same ident.

Common situations: Reusing a backend generic `B` or model generic `T` on both a real submodule and a skipped metadata/config field; copy-pasting fields and adding #[module(skip)] to one without renaming its generic; migrating structs to skip serialization of some fields.

Related errors


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