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

  1. Remove `ExtractField` from the enum/union's derive list — the metadata it generates only exists for structs.
  2. If each variant's payload needs field introspection, put `ExtractField` on the payload structs instead.
  3. 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

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


AI-assisted analysis of GraphiteEditor/Graphite@c507b35645 (2026-08-16). Data as JSON: /api/errors/20bd7a0c30675a5a. Report an issue: GitHub.