GraphiteEditor/Graphite · error · syn::Error
ExtractField only works on structs
Error message
ExtractField only works on structs
What it means
The `ExtractField` derive is defined only for structs; applying it to an enum or union fails this early check in the derive implementation. The macro walks `Data::Struct` fields to build compile-time field metadata, which has no meaning for enum variants or union fields.
Source
Thrown at proc-macros/src/extract_fields.rs:19
use crate::helpers::clean_rust_type_syntax;
use proc_macro2::{Span, TokenStream};
use quote::{ToTokens, format_ident, quote};
use syn::{Data, DeriveInput, Fields, Type, parse2};
pub fn derive_extract_field_impl(input: TokenStream) -> syn::Result<TokenStream> {
let input = parse2::<DeriveInput>(input)?;
let struct_name = &input.ident;
let generics = &input.generics;
let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
let line_number = struct_name.span().start().line;
let fields = match &input.data {
Data::Struct(data) => match &data.fields {
Fields::Named(fields) => &fields.named,
_ => return Err(syn::Error::new(Span::call_site(), "ExtractField only works on structs with named fields")),
},
_ => return Err(syn::Error::new(Span::call_site(), "ExtractField only works on structs")),
};
let mut field_line = Vec::new();
// Extract field names and types as strings at compile time
let field_info = fields
.iter()
.map(|field| {
let ident = field.ident.as_ref().unwrap();
let name = ident.to_string();
let ty = clean_rust_type_syntax(field.ty.to_token_stream().to_string());
let line = ident.span().start().line;
field_line.push(line);
(name, ty)
})
.collect::<Vec<_>>();
let field_str = field_info.into_iter().map(|(name, ty)| (format!("{name}: {ty}")));
View on GitHub (pinned to c507b35645)
Solutions
- Remove `ExtractField` from the enum/union's derive list — the metadata it generates only exists for structs.
- If each variant's payload needs field introspection, put `ExtractField` on the payload structs instead.
- If the type should be a struct, revert the enum conversion.
Example fix
// before
#[derive(ExtractField)]
enum ShapeData {
Rect { w: f64, h: f64 },
}
// after
#[derive(ExtractField)]
struct Rect {
w: f64,
h: f64,
}
enum ShapeData {
Rect(Rect),
} Defensive patterns
Strategy: validation
Prevention
- Keep ExtractField out of enum/union derive lists.
- When converting a struct to an enum, prune derives that are struct-only.
- Derive ExtractField on variant payload structs instead.
When it happens
Trigger: Applying `#[derive(ExtractField)]` to an `enum` or `union` item. Any `Data` variant other than `Data::Struct` hits the second error arm.
Common situations: A blanket derive added to every message type in a crate, or moving a type from struct to enum (e.g. introducing a `None` state) while the old derive list stays in place.
Related errors
- Tried to derive AsMessage for non-enum
- Tried to derive a discriminant for non-enum
- ExtractField only works on structs with named fields
- Tried to derive HierarchicalTree for non-enum
- The `{variant_type}` message should be defined as a struct-s
AI-assisted analysis of GraphiteEditor/Graphite@c507b35645 (2026-08-16).
Data as JSON: /api/errors/20bd7a0c30675a5a.
Report an issue: GitHub.