{"id":"3690a299ad529506","repo":"actix/actix-web","slug":"multipartform-can-only-be-derived-for-structs","errorCode":null,"errorMessage":"`MultipartForm` can only be derived for structs","messagePattern":"`MultipartForm` can only be derived for structs","errorType":"exception","errorClass":"syn::Error","httpStatus":null,"severity":"error","filePath":"actix-multipart-derive/src/lib.rs","lineNumber":66,"sourceCode":"    ty: &'t Type,\n}\n\n/// Implements `MultipartCollect` for a struct so that it can be used with the `MultipartForm`\n/// extractor.\n///\n/// See [`actix_multipart::form::MultipartForm`] for supported fields and attributes.\n///\n/// [`actix_multipart::form::MultipartForm`]: https://docs.rs/actix-multipart/latest/actix_multipart/form/struct.MultipartForm.html\n#[proc_macro_derive(MultipartForm, attributes(multipart))]\npub fn impl_multipart_form(input: proc_macro::TokenStream) -> proc_macro::TokenStream {\n    let input: syn::DeriveInput = parse_macro_input!(input);\n\n    let name = &input.ident;\n\n    let data_struct = match &input.data {\n        syn::Data::Struct(data_struct) => data_struct,\n        _ => {\n            return compile_err(syn::Error::new(\n                input.ident.span(),\n                \"`MultipartForm` can only be derived for structs\",\n            ))\n        }\n    };\n\n    let fields = match &data_struct.fields {\n        syn::Fields::Named(fields_named) => fields_named,\n        _ => {\n            return compile_err(syn::Error::new(\n                input.ident.span(),\n                \"`MultipartForm` can only be derived for a struct with named fields\",\n            ))\n        }\n    };\n\n    let attrs = match MultipartFormAttrs::from_derive_input(&input) {\n        Ok(attrs) => attrs,","sourceCodeStart":48,"sourceCodeEnd":84,"githubUrl":"https://github.com/actix/actix-web/blob/937960ca67f20e14ffe2a075bf6d4593502be12c/actix-multipart-derive/src/lib.rs#L48-L84","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\n#[derive(MultipartForm)]\nenum Form {\n    A { name: String },\n    B { file: Field },\n}\n\n// after\n#[derive(MultipartForm)]\nstruct FormA { name: String }\n\n#[derive(MultipartForm)]\nstruct FormB { file: Field }","handlingStrategy":"validation","validationCode":"// Before adding the derive, confirm the item is a struct with named fields.\n// There is no runtime API to guard; this is a compile-time check. Verify:\n//   - the type is declared with `struct Name { ... }`\n//   - it is not an `enum` or `union`\n// If unsure, the compiler/macro will flag it; fix the type declaration.","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Only attach #[derive(MultipartForm)] to plain structs.","Keep one struct per multipart payload shape instead of enums."],"tags":["rust","actix","actix-multipart","macro","compile-time","derive"],"analyzedSha":"937960ca67f20e14ffe2a075bf6d4593502be12c","analyzedAt":"2026-08-06T01:15:46.978Z","schemaVersion":2}