GraphiteEditor/Graphite · error · syn::Error
The `{variant_type}` message should be defined as a struct-s
Error message
The `{variant_type}` message should be defined as a struct-style (not tuple-style) enum variant to maintain consistent formatting across all editor messages.
Replace `{field_types}` with named fields using {{curly braces}} instead of positional fields using (parentheses). What it means
Every variant of a `HierarchicalTree`-derived enum must use named (struct-style) fields, not positional (tuple-style) fields. The macro renders each variant as a DebugMessageTree of `field_name: value` strings, and tuple variants have no field names to print — so the derive reports the offending variant and its positional field types and asks for curly-brace form.
Source
Thrown at proc-macros/src/hierarchical_tree.rs:69
let error_msg = match fields.unnamed.len() {
0 => format!("Remove the unnecessary `()` from the `{variant_type}` message enum variant."),
1 => {
let field_type = &fields.unnamed.first().unwrap().ty;
format!(
"The `{variant_type}` message should be defined as a struct-style (not tuple-style) enum variant to maintain consistent formatting across all editor messages.\n\
Replace `{}` with a named field using {{curly braces}} instead of a positional field using (parentheses).",
field_type.to_token_stream()
)
}
_ => {
let field_types = fields.unnamed.iter().map(|f| f.ty.to_token_stream().to_string()).collect::<Vec<_>>().join(", ");
format!(
"The `{variant_type}` message should be defined as a struct-style (not tuple-style) enum variant to maintain consistent formatting across all editor messages.\n\
Replace `{field_types}` with named fields using {{curly braces}} instead of positional fields using (parentheses)."
)
}
};
Err(syn::Error::new(Span::call_site(), error_msg))
}
}
Fields::Named(fields) => {
let names = fields.named.iter().map(|f| f.ident.as_ref().unwrap());
let ty = fields.named.iter().map(|f| clean_rust_type_syntax(f.ty.to_token_stream().to_string()));
Ok(quote! {
{
let mut field_names = Vec::new();
#(field_names.push(format!("{}: {}",stringify!(#names), #ty));)*
let mut variant_tree = DebugMessageTree::new(stringify!(#variant_type));
variant_tree.add_fields(field_names);
message_tree.add_variant(variant_tree);
}
})
}
}
})
.collect();View on GitHub (pinned to c507b35645)
Solutions
- Convert the offending variant to named fields: `AddLayer { id: u64, name: String }`.
- Update construction sites to use `AddLayer { id, name }` struct-literal syntax (the compiler will list them all).
- Scan the whole enum for other tuple-style variants — the macro reports one at a time.
Example fix
// before
#[derive(HierarchicalTree)]
enum Message {
AddLayer(u64, String),
}
// after
#[derive(HierarchicalTree)]
enum Message {
AddLayer {
id: u64,
name: String,
},
} Defensive patterns
Strategy: validation
Prevention
- Standardize on struct-style (named-field) variants for all message enums.
- Enable a clippy lint like `clippy::upper_case_acronyms`-style team convention or a custom lint pass to flag tuple variants in message crates.
- Fix all variants in one pass after the first error — the macro reports them one at a time.
When it happens
Trigger: Declaring a variant like `AddLayer(u64, String)` inside an enum that derives `HierarchicalTree`. The `Fields::Unnamed` arm builds the error message listing the tuple field types.
Common situations: Adding a quick new message variant in tuple style (the ergonomic Rust default), or converting an existing enum to derive HierarchicalTree without restyling its variants. Note sibling macros such as editor_commands already enforce the named-field convention, so mixed codebases drift here first.
Related errors
- ExtractField only works on structs with named fields
- Tried to derive AsMessage for non-enum
- Tried to derive a discriminant for non-enum
- ExtractField only works on structs
- Tried to derive HierarchicalTree for non-enum
AI-assisted analysis of GraphiteEditor/Graphite@c507b35645 (2026-08-16).
Data as JSON: /api/errors/6e0770eebadfc767.
Report an issue: GitHub.