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

  1. Convert the offending variant to named fields: `AddLayer { id: u64, name: String }`.
  2. Update construction sites to use `AddLayer { id, name }` struct-literal syntax (the compiler will list them all).
  3. 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

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


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