{"record":{"id":"7f5f38eea0ddb51b","repo":"linebender/druid","slug":"lens-implementations-cannot-be-derived-from-enums","errorCode":null,"errorMessage":"Lens implementations cannot be derived from enums","messagePattern":"Lens implementations cannot be derived from enums","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"druid-derive/src/lens.rs","lineNumber":15,"sourceCode":"// Copyright 2019 the Druid Authors\n// SPDX-License-Identifier: Apache-2.0\n\nuse super::attr::{FieldKind, Fields, LensAttrs};\nuse proc_macro2::{Ident, Span};\nuse quote::quote;\nuse std::collections::HashSet;\nuse syn::{spanned::Spanned, Data, GenericParam, TypeParam};\n\npub(crate) fn derive_lens_impl(\n    input: syn::DeriveInput,\n) -> Result<proc_macro2::TokenStream, syn::Error> {\n    match &input.data {\n        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(),","sourceCodeStart":1,"sourceCodeEnd":33,"githubUrl":"https://github.com/linebender/druid/blob/0f8b1195e4e073f9597f2865299c3d18f8e4005f/druid-derive/src/lens.rs#L1-L33","documentation":"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.)","triggerScenarios":"Writing #[derive(Lens)] on an `enum` definition, typically while trying to derive both Data and Lens on a shared type that is an enum.","commonSituations":"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.","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."],"exampleFix":"// before\n#[derive(Data, Lens)]\nenum Shape { Circle(f64), Square(f64) }\n// after\n#[derive(Data)]\nenum Shape { Circle(Circle), Square(Square) }\n\n#[derive(Data, Lens)]\nstruct Circle { radius: f64 }","handlingStrategy":"validation","validationCode":"// CI check: forbid Lens derive on enums\n// ! grep -rPzo '(?s)#[^\n]*derive\\s*\\([^)]*\\bLens\\b[^)]*\\)(?s:.)*?\\benum\\b' src/","typeGuard":null,"tryCatchPattern":null,"preventionTips":["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."],"tags":["derive-macro","proc-macro","compile-time","enums"],"backgroundTag":"incompatible-source-type","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"}