{"record":{"id":"f6ca8804523dacb2","repo":"GraphiteEditor/Graphite","slug":"extractfield-only-works-on-structs-with-named-fiel","errorCode":null,"errorMessage":"ExtractField only works on structs with named fields","messagePattern":"ExtractField only works on structs with named fields","errorType":"validation","errorClass":"syn::Error","httpStatus":null,"severity":"error","filePath":"proc-macros/src/extract_fields.rs","lineNumber":17,"sourceCode":"use crate::helpers::clean_rust_type_syntax;\nuse proc_macro2::{Span, TokenStream};\nuse quote::{ToTokens, format_ident, quote};\nuse syn::{Data, DeriveInput, Fields, Type, parse2};\n\npub fn derive_extract_field_impl(input: TokenStream) -> syn::Result<TokenStream> {\n\tlet input = parse2::<DeriveInput>(input)?;\n\tlet struct_name = &input.ident;\n\tlet generics = &input.generics;\n\tlet (impl_generics, ty_generics, where_clause) = generics.split_for_impl();\n\n\tlet line_number = struct_name.span().start().line;\n\n\tlet fields = match &input.data {\n\t\tData::Struct(data) => match &data.fields {\n\t\t\tFields::Named(fields) => &fields.named,\n\t\t\t_ => return Err(syn::Error::new(Span::call_site(), \"ExtractField only works on structs with named fields\")),\n\t\t},\n\t\t_ => return Err(syn::Error::new(Span::call_site(), \"ExtractField only works on structs\")),\n\t};\n\n\tlet mut field_line = Vec::new();\n\t// Extract field names and types as strings at compile time\n\tlet field_info = fields\n\t\t.iter()\n\t\t.map(|field| {\n\t\t\tlet ident = field.ident.as_ref().unwrap();\n\t\t\tlet name = ident.to_string();\n\t\t\tlet ty = clean_rust_type_syntax(field.ty.to_token_stream().to_string());\n\t\t\tlet line = ident.span().start().line;\n\t\t\tfield_line.push(line);\n\t\t\t(name, ty)\n\t\t})\n\t\t.collect::<Vec<_>>();\n","sourceCodeStart":1,"sourceCodeEnd":35,"githubUrl":"https://github.com/GraphiteEditor/Graphite/blob/c507b356453361e31638b8bff8f6d46b6da2961e/proc-macros/src/extract_fields.rs#L1-L35","documentation":"The `ExtractField` derive only supports structs with named fields because it generates a `field_types()` introspection listing each field's name, type, and source line (used for editor message documentation). Tuple structs and unit structs have no field names to report, so the derive aborts with this compile-time error.","triggerScenarios":"Applying `#[derive(ExtractField)]` to a tuple struct (`struct Foo(u32, String);`) or a unit struct (`struct Marker;`). Only `Fields::Named` is accepted.","commonSituations":"Adding the derive to a newtype wrapper or marker type during a refactor, or applying a blanket `#[derive(Debug, Clone, ExtractField)]` via editor tooling/templating without checking the struct shape.","solutions":["Convert the tuple struct to named fields: `struct Foo { value: u32, name: String }`.","If the type must stay a tuple struct, remove `ExtractField` from its derive list.","For unit structs, remove the derive — there are no fields to extract."],"exampleFix":"// before\n#[derive(ExtractField)]\nstruct LayerSnapshot(u64, String);\n\n// after\n#[derive(ExtractField)]\nstruct LayerSnapshot {\n\tid: u64,\n\tname: String,\n}","handlingStrategy":"validation","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":["Only derive ExtractField on structs with named fields.","Prefer named-field structs for types that feed the editor message-doc pipeline.","Grep for tuple structs before adding the derive: `rg '#[derive(.*ExtractField' -A2`."],"tags":["rust","proc-macro","derive","named-fields"],"backgroundTag":"derive-macro-input-validation","analyzedSha":"c507b356453361e31638b8bff8f6d46b6da2961e","analyzedAt":"2026-08-16T21:57:18.596Z","schemaVersion":2},"datasetVersion":"2026-08-16T23:17:17.608Z"}