linebender/druid · error
Lens implementations cannot be derived from enums
Error message
Lens implementations cannot be derived from enums
What it means
The Lens derive only supports structs; lenses model a path into a single value, which enums do not provide. Applying #[derive(Lens)] to an enum is rejected at compile time with this error at the enum keyword's span. (Unions are likewise rejected with a sibling message.)
Solutions
- Remove #[derive(Lens)] from the enum; keep only #[derive(Data)].
- If you need a lens into one variant, use druid's lens combinators (lens::LensExt, Lens::then, or a custom Lens impl) instead of deriving.
- Move the lens target into a struct (e.g. the variant's payload) and derive Lens on that struct.
Example fix
// before
#[derive(Data, Lens)]
enum Shape { Circle(f64), Square(f64) }
// after
#[derive(Data)]
enum Shape { Circle(Circle), Square(Square) }
#[derive(Data, Lens)]
struct Circle { radius: f64 } Defensive patterns
Strategy: validation
Validate before calling
// CI check: forbid Lens derive on enums // ! grep -rPzo '(?s)#[^ ]*derive\s*\([^)]*\bLens\b[^)]*\)(?s:.)*?\benum\b' src/
Prevention
- Only derive Lens on structs; enums get #[derive(Data)] only.
- Use lens combinators (Lens::then, lens::InArc, custom Lens impls) to reach enum variants.
- Split variant payloads into structs if you need derived lenses on their fields.
- Run `cargo check` after adding derives; the error points at the enum keyword.
When it happens
Trigger: Writing #[derive(Lens)] on an `enum` definition, typically while trying to derive both Data and Lens on a shared type that is an enum.
Common situations: Copy-pasting derive lists from a struct to an enum, misunderstanding that Lens is struct-only in druid, macro-generated code adding Lens to all types.
Understand the failure class
Background: "is not a compatible type" / "cannot merge" errors: when a value's type doesn't match what the library requires — this error's family across 65 libraries.
Related errors
- Unknown attribute
- Expected attribute list (the form #[data(one, two)])
- Duplicate attribute
- Expected attribute list (the form #[lens(one, two)])
- expected str, found... something else
AI-assisted analysis of linebender/druid@0f8b1195e4 (2026-09-10).
Data as JSON: /api/errors/7f5f38eea0ddb51b.
Report an issue: GitHub.
Appendix: source
Thrown at druid-derive/src/lens.rs:15
// Copyright 2019 the Druid Authors
// SPDX-License-Identifier: Apache-2.0
use super::attr::{FieldKind, Fields, LensAttrs};
use proc_macro2::{Ident, Span};
use quote::quote;
use std::collections::HashSet;
use syn::{spanned::Spanned, Data, GenericParam, TypeParam};
pub(crate) fn derive_lens_impl(
input: syn::DeriveInput,
) -> Result<proc_macro2::TokenStream, syn::Error> {
match &input.data {
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(),View on GitHub (pinned to 0f8b1195e4)