actix/actix-web · error · syn::Error
`MultipartForm` can only be derived for structs
Error message
`MultipartForm` can only be derived for structs
What it means
The `#[derive(MultipartForm)]` proc macro only accepts plain structs. At actix-multipart-derive/src/lib.rs:66 the macro matches `syn::Data::Struct` and rejects enums and unions outright, because the generated `MultipartCollect` impl constructs `Self { ... }` field-by-field, which is only valid syntax for structs. Anything else would produce nonsensical code, so the macro fails fast.
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 937960ca67)
Solutions
- Change the target type from an enum/union to a struct with named fields.
- If you need multiple payload shapes, wrap them: use one struct per shape and pick the struct in the handler rather than a single enum.
- Remove the `#[derive(MultipartForm)]` attribute if this type is not actually a multipart form.
Example fix
// before
#[derive(MultipartForm)]
enum Form {
A { name: String },
B { file: Field },
}
// after
#[derive(MultipartForm)]
struct FormA { name: String }
#[derive(MultipartForm)]
struct FormB { file: Field } Defensive patterns
Strategy: validation
Validate before calling
// Before adding the derive, confirm the item is a struct with named fields.
// There is no runtime API to guard; this is a compile-time check. Verify:
// - the type is declared with `struct Name { ... }`
// - it is not an `enum` or `union`
// If unsure, the compiler/macro will flag it; fix the type declaration. Prevention
- Only attach #[derive(MultipartForm)] to plain structs.
- Keep one struct per multipart payload shape instead of enums.
When it happens
Trigger: Annotating an `enum` or `union` (e.g. `#[derive(MultipartForm)] enum Form {...}`) with the derive. Also happens if a type alias or macro-generated item that is not a struct carries the attribute.
Common situations: Modeling a multipart payload as an enum of variants (a natural design for "one of several shapes"), or copy-pasting a serde enum that was previously serialized and trying to reuse it as a multipart form type.
Related errors
- `MultipartForm` can only be derived for a struct with named
- Could not parse size limit `{}`: {}
- Multiple fields named: `{}`
- invalid service definition, expected #[<method>("<path>")]
- Multiple paths specified! There should be only one.
AI-assisted analysis of actix/actix-web@937960ca67 (2026-08-06).
Data as JSON: /data/errors/3690a299ad529506.json.
Report an issue: GitHub.