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

  1. Remove #[derive(Lens)] from the enum; keep only #[derive(Data)].
  2. 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.
  3. 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

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


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)