linebender/druid · error
Lens implementations can only be derived from structs with…
Error message
Lens implementations can only be derived from structs with named fields
What it means
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().
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.
Example fix
// before
#[derive(Clone, Lens)]
struct Radius(f64);
// after
#[derive(Clone, Lens)]
struct Radius { value: f64 } Defensive patterns
Strategy: validation
Validate before calling
// ensure the derive target has named fields:
// struct Good { field: T } OK
// struct Bad(T); tuple -> rejected
// struct Worse; unit -> rejected Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
Related errors
- Lens implementations cannot be derived from unions
- Unknown attribute
- Unwrap named called on unnamed FieldIdent
- Expected attribute list (the form #[data(one, two)])
- Duplicate attribute
AI-assisted analysis of linebender/druid@0f8b1195e4 (2026-09-10).
Data as JSON: /api/errors/5ed6e694023b1da4.
Report an issue: GitHub.
Appendix: source
Thrown at druid-derive/src/lens.rs:32
Data::Struct(_) => derive_struct(&input),
Data::Enum(e) => Err(syn::Error::new(
e.enum_token.span(),
"Lens implementations cannot be derived from enums",
)),
Data::Union(u) => Err(syn::Error::new(
u.union_token.span(),
"Lens implementations cannot be derived from unions",
)),
}
}
fn derive_struct(input: &syn::DeriveInput) -> Result<proc_macro2::TokenStream, syn::Error> {
let ty = &input.ident;
let fields = if let syn::Data::Struct(syn::DataStruct { fields, .. }) = &input.data {
Fields::<LensAttrs>::parse_ast(fields)?
} else {
return Err(syn::Error::new(
input.span(),
"Lens implementations can only be derived from structs with named fields",
));
};
if fields.kind != FieldKind::Named {
return Err(syn::Error::new(
input.span(),
"Lens implementations can only be derived from structs with named fields",
));
}
let twizzled_name = if is_camel_case(&ty.to_string()) {
let temp_name = format!("{}_derived_lenses", to_snake_case(&ty.to_string()));
proc_macro2::Ident::new(&temp_name, proc_macro2::Span::call_site())
} else {
return Err(syn::Error::new(
ty.span(),View on GitHub (pinned to 0f8b1195e4)