{"record":{"id":"4b45e20d8fabad60","repo":"quickwit-oss/quickwit","slug":"serde-multikey-was-applied-to-a-tuple-struct-or","errorCode":null,"errorMessage":"`serde_multikey` was applied to a tuple-struct or an empty struct","messagePattern":"`serde_multikey` was applied to a tuple-struct or an empty struct","errorType":"exception","errorClass":"proc-macro compile error","httpStatus":null,"severity":"error","filePath":"quickwit/quickwit-macros/src/lib.rs","lineNumber":157,"sourceCode":"    let proxy_ident = Ident::new(&format!(\"__MultiKey{}\", input.ident), input.ident.span());\n\n    input.ident = proxy_ident.clone();\n    input.vis = Visibility::Inherited;\n    // TODO wait for https://github.com/juhaku/utoipa/issues/704 to re-enable\n    // input.attrs.append(&mut Attribute::parse_outer\n    // .parse_str(&\"#[doc(hidden)]\")\n    // .unwrap());\n\n    let (ser, de) = get_ser_de(&input.attrs)?;\n\n    let mut pass_through = Vec::<Ident>::new();\n    let mut final_fields = Punctuated::<Field, Token![,]>::new();\n    let mut try_from_conv = Vec::<TokenStream2>::new();\n    let mut into_pre_conv = Vec::<TokenStream2>::new();\n    let mut into_in_conv = Vec::<TokenStream2>::new();\n\n    let Fields::Named(FieldsNamed { brace_token, named }) = input.fields else {\n        return Err(Error::new(\n            Span::call_site(),\n            \"`serde_multikey` was applied to a tuple-struct or an empty struct\",\n        ));\n    };\n    for pair in named.into_pairs() {\n        let (mut field, ponct) = pair.into_tuple();\n        // we are in a \"normal\" struct, not a tuple-struct, unwrap is fine.\n        let field_name = field.ident.clone().unwrap();\n\n        let (field_config, attrs) = parse_attributes(field.attrs, &field_name)?;\n        field.attrs = attrs;\n\n        if let Some(field_config) = field_config {\n            let value = Ident::new(\"value\", Span::call_site());\n            for field in &field_config.proxy_fields {\n                final_fields.push(field.clone());\n            }\n            match (ser, field_config.get_into(&value)) {","sourceCodeStart":139,"sourceCodeEnd":175,"githubUrl":"https://github.com/quickwit-oss/quickwit/blob/a39730c5cdcd1a4fe798403737ae293999ea21f8/quickwit/quickwit-macros/src/lib.rs#L139-L175","documentation":"generate_proxy_struct builds a proxy struct mirroring the target's fields, which requires named fields (Fields::Named). Tuple structs, unit structs, and structs with unnamed fields cannot be mirrored, so the macro fails compilation with this message.","triggerScenarios":"Applying #[serde_multikey(...)] to a tuple struct like `struct Wrapper(String);`, a unit struct `struct Unit;`, or any struct without named fields.","commonSituations":"Trying to make a newtype wrapper multi-key-capable; refactoring a named struct into a tuple struct while keeping the attribute.","solutions":["Convert the struct to use named fields, e.g. `struct Wrapper { value: String }`.","Remove the #[serde_multikey] attribute if multi-key behavior is not actually needed."],"exampleFix":"// before\n#[serde_multikey(fields(v))]\nstruct Wrapper(String);\n// after\n#[derive(Serialize, Deserialize)]\n#[serde_multikey(fields(v))]\nstruct Wrapper { v: String }","handlingStrategy":"validation","validationCode":"// serde_multikey requires named fields; verify struct shape:\n// struct Good { key: String }        // OK\n// struct Bad(String);                // NOT supported\n// struct Unit;                       // NOT supported","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Use named-field structs with serde_multikey","Avoid converting multikey structs to newtype/tuple form during refactors","If you need a newtype, drop the attribute and write serde impls manually"],"tags":["rust","proc-macro","serde","compile-time"],"backgroundTag":"unsupported-operation","analyzedSha":"a39730c5cdcd1a4fe798403737ae293999ea21f8","analyzedAt":"2026-09-08T13:19:37.784Z","contentChangedAt":"2026-09-08T13:19:37.784Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}