actix/actix-web · critical · syn::Error

`MultipartForm` can only be derived for structs

Error message

`MultipartForm` can only be derived for structs

What it means

A compile-time syn::Error emitted by the MultipartForm derive macro (multipart-derive/src/lib.rs:66) when #[derive(MultipartForm)] is applied to anything other than a struct - i.e. an enum or union. The macro matches input.data against syn::Data::Struct (lib.rs:63) and, on mismatch, returns this error via compile_err. There is a separate, similar message for structs without named fields (lib.rs:76).

Solutions

  1. Define a struct with named fields and derive MultipartForm on it.
  2. If you need variants, wrap the struct in an enum manually and extract MultipartForm on the inner struct.
  3. Ensure all fields are named (not tuple/struct-unit); the macro requires syn::Fields::Named (lib.rs:74).

Example fix

// before
#[derive(MultipartForm)]
enum Shape { A(Text<String>), B(TempFile) } // compile error

// after
#[derive(MultipartForm)]
struct Form { label: Text<String>, file: Option<TempFile> }
Defensive patterns

Strategy: type-guard

Validate before calling

// The macro only accepts structs with named fields; check before annotating

Type guard

// Only derive on structs (named fields); never on enums/unions
#[derive(MultipartForm)]
struct Upload {
    name: Text<String>,
    file: TempFile,
}
// enum E { ... } // do NOT put #[derive(MultipartForm)] here

Prevention

When it happens

Trigger: Annotating an enum or union with #[derive(MultipartForm)]: e.g. `#[derive(MultipartForm)] enum E { ... }`. The build fails with this message pointing at the type's span.

Common situations: Trying to model a discriminated form payload as an enum; copy-pasting the derive onto the wrong item; misunderstanding that the macro only supports plain structs with named fields.

Related errors


AI-assisted analysis of actix/actix-web@4d435abc28 (2026-08-09). Data as JSON: /api/errors/3690a299ad529506. Report an issue: GitHub.

Appendix: source

Thrown at actix-multipart-derive/src/lib.rs:66

    ty: &'t Type,
}

/// Implements `MultipartCollect` for a struct so that it can be used with the `MultipartForm`
/// extractor.
///
/// See [`actix_multipart::form::MultipartForm`] for supported fields and attributes.
///
/// [`actix_multipart::form::MultipartForm`]: https://docs.rs/actix-multipart/latest/actix_multipart/form/struct.MultipartForm.html
#[proc_macro_derive(MultipartForm, attributes(multipart))]
pub fn impl_multipart_form(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
    let input: syn::DeriveInput = parse_macro_input!(input);

    let name = &input.ident;

    let data_struct = match &input.data {
        syn::Data::Struct(data_struct) => data_struct,
        _ => {
            return compile_err(syn::Error::new(
                input.ident.span(),
                "`MultipartForm` can only be derived for structs",
            ))
        }
    };

    let fields = match &data_struct.fields {
        syn::Fields::Named(fields_named) => fields_named,
        _ => {
            return compile_err(syn::Error::new(
                input.ident.span(),
                "`MultipartForm` can only be derived for a struct with named fields",
            ))
        }
    };

    let attrs = match MultipartFormAttrs::from_derive_input(&input) {
        Ok(attrs) => attrs,

View on GitHub (pinned to 4d435abc28)