{"id":"73b0dcfae6a23a9c","repo":"actix/actix-web","slug":"multipartform-can-only-be-derived-for-a-struct-w","errorCode":null,"errorMessage":"`MultipartForm` can only be derived for a struct with named fields","messagePattern":"`MultipartForm` can only be derived for a struct with named fields","errorType":"exception","errorClass":"syn::Error","httpStatus":null,"severity":"error","filePath":"actix-multipart-derive/src/lib.rs","lineNumber":76,"sourceCode":"pub 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,\n        Err(err) => return err.write_errors().into(),\n    };\n\n    // Parse the field attributes\n    let parsed = match fields\n        .named\n        .iter()\n        .map(|field| {\n            let rust_name = field.ident.as_ref().unwrap();\n            let attrs = FieldAttrs::from_field(field).map_err(|err| err.write_errors())?;","sourceCodeStart":58,"sourceCodeEnd":94,"githubUrl":"https://github.com/actix/actix-web/blob/937960ca67f20e14ffe2a075bf6d4593502be12c/actix-multipart-derive/src/lib.rs#L58-L94","documentation":"Even among structs, the derive requires named fields. At actix-multipart-derive/src/lib.rs:76 only `syn::Fields::Named` is accepted; tuple structs (`struct Foo(String)`) and unit structs (`struct Foo;`) are rejected because the generated `from_state` impl references each field by name (e.g. `rust_name: <Ty>::from_state(...)`), which is impossible without names.","triggerScenarios":"Deriving `MultipartForm` on a tuple struct like `struct Upload(File);` or a unit struct `struct Empty;`.","commonSituations":"Newtype wrappers around a single field, or empty marker structs that accidentally inherit the attribute during a refactor.","solutions":["Convert tuple/unit fields to named fields: `struct Upload { file: File }`.","If the struct is intentionally empty, remove the derive (an empty multipart form is usually a mistake)."],"exampleFix":"// before\n#[derive(MultipartForm)]\nstruct Upload(File);\n\n// after\n#[derive(MultipartForm)]\nstruct Upload {\n    file: Field,\n}","handlingStrategy":"validation","validationCode":"// Compile-time: ensure fields are named. Check the declaration uses\n// `struct Name { field: Type, ... }`, not `struct Name(Type)` or `struct Name;`.","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Avoid tuple/unit structs for multipart form types.","Name every field descriptively to match the form part names."],"tags":["rust","actix","actix-multipart","macro","compile-time","derive"],"analyzedSha":"937960ca67f20e14ffe2a075bf6d4593502be12c","analyzedAt":"2026-08-06T01:15:46.978Z","schemaVersion":2}