{"record":{"id":"5ed6e694023b1da4","repo":"linebender/druid","slug":"lens-implementations-can-only-be-derived-from-stru","errorCode":null,"errorMessage":"Lens implementations can only be derived from structs with named fields","messagePattern":"Lens implementations can only be derived from structs with named fields","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"druid-derive/src/lens.rs","lineNumber":32,"sourceCode":"        Data::Struct(_) => derive_struct(&input),\n        Data::Enum(e) => Err(syn::Error::new(\n            e.enum_token.span(),\n            \"Lens implementations cannot be derived from enums\",\n        )),\n        Data::Union(u) => Err(syn::Error::new(\n            u.union_token.span(),\n            \"Lens implementations cannot be derived from unions\",\n        )),\n    }\n}\n\nfn derive_struct(input: &syn::DeriveInput) -> Result<proc_macro2::TokenStream, syn::Error> {\n    let ty = &input.ident;\n\n    let fields = if let syn::Data::Struct(syn::DataStruct { fields, .. }) = &input.data {\n        Fields::<LensAttrs>::parse_ast(fields)?\n    } else {\n        return Err(syn::Error::new(\n            input.span(),\n            \"Lens implementations can only be derived from structs with named fields\",\n        ));\n    };\n\n    if fields.kind != FieldKind::Named {\n        return Err(syn::Error::new(\n            input.span(),\n            \"Lens implementations can only be derived from structs with named fields\",\n        ));\n    }\n\n    let twizzled_name = if is_camel_case(&ty.to_string()) {\n        let temp_name = format!(\"{}_derived_lenses\", to_snake_case(&ty.to_string()));\n        proc_macro2::Ident::new(&temp_name, proc_macro2::Span::call_site())\n    } else {\n        return Err(syn::Error::new(\n            ty.span(),","sourceCodeStart":14,"sourceCodeEnd":50,"githubUrl":"https://github.com/linebender/druid/blob/0f8b1195e4e073f9597f2865299c3d18f8e4005f/druid-derive/src/lens.rs#L14-L50","documentation":"The Lens derive requires a struct whose fields are declared with names (`struct Foo { a: u32 }`). When `derive_struct` in druid-derive is handed a struct whose fields are unnamed (tuple struct) or a unit struct, the parsed Fields::<LensAttrs> cannot be produced and the macro fails with this message at input.span().","triggerScenarios":"Applying `#[derive(Lens)]` to a tuple struct like `struct Point(f64, f64)` or a unit struct like `struct Marker;`. Raised in derive_struct called from derive_lens_impl.","commonSituations":"Deriving Lens on newtype wrappers (`struct Wrapper(inner: T)` written as tuple) or marker types; porting code where a struct was changed from named fields to a tuple struct after the derive was added.","solutions":["Convert the tuple struct to a struct with named fields, e.g. `struct Wrapper { inner: T }`.","If fields must stay unnamed, remove the derive and write a manual `impl Lens` for the type.","For a unit struct there is nothing to lens; remove the Lens derive entirely.","Wrap the tuple struct in a named-field struct and derive Lens on the wrapper."],"exampleFix":"// before\n#[derive(Clone, Lens)]\nstruct Radius(f64);\n\n// after\n#[derive(Clone, Lens)]\nstruct Radius { value: f64 }","handlingStrategy":"validation","validationCode":"// ensure the derive target has named fields:\n// struct Good { field: T }   OK\n// struct Bad(T);              tuple -> rejected\n// struct Worse;               unit  -> rejected","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Only derive Lens on structs written with `{ }` field syntax.","For newtypes, add an explicit named field (`inner: T`) instead of a tuple.","Review generated code that emits tuple structs for Lens targets."],"tags":["rust","derive-macro","lens","compile-time"],"backgroundTag":"schema-validation-failed","analyzedSha":"0f8b1195e4e073f9597f2865299c3d18f8e4005f","analyzedAt":"2026-09-10T14:27:34.582Z","contentChangedAt":"2026-09-10T14:27:34.582Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}