GraphiteEditor/Graphite · error · syn::Error
Tried to derive HierarchicalTree for non-enum
Error message
Tried to derive HierarchicalTree for non-enum
What it means
The `HierarchicalTree` derive generates DebugMessageTree formatting for editor messages and is implemented exclusively for enums (each variant becomes a tree node). Applying it to a struct or union fails this compile-time check because there are no variants to walk.
Source
Thrown at proc-macros/src/hierarchical_tree.rs:14
use crate::helpers::clean_rust_type_syntax;
use proc_macro2::{Span, TokenStream};
use quote::{ToTokens, quote};
use syn::{Data, DeriveInput, Fields, Type, parse2};
pub fn generate_hierarchical_tree(input: TokenStream) -> syn::Result<TokenStream> {
let input = parse2::<DeriveInput>(input)?;
let input_type = &input.ident;
let line_number = input_type.span().start().line;
let data = match &input.data {
Data::Enum(data) => data,
_ => return Err(syn::Error::new(Span::call_site(), "Tried to derive HierarchicalTree for non-enum")),
};
let build_message_tree: Result<Vec<_>, syn::Error> = data
.variants
.iter()
.map(|variant| {
let variant_type = &variant.ident;
let has_child = variant
.attrs
.iter()
.any(|attr| attr.path().get_ident().is_some_and(|ident| ident == "sub_discriminant" || ident == "child"));
match &variant.fields {
Fields::Unit => Ok(quote! {
message_tree.add_variant(DebugMessageTree::new(stringify!(#variant_type)));
}),
Fields::Unnamed(fields) => {View on GitHub (pinned to c507b35645)
Solutions
- Remove `HierarchicalTree` from the struct/union's derive list.
- If the type is really a message, model it as an enum with variants and keep the derive there.
- For structs used as variant payloads, derive it on the wrapping enum and let the generated code stringify the payload fields.
Example fix
// before
#[derive(HierarchicalTree)]
struct DocumentMessage {
name: String,
}
// after
#[derive(HierarchicalTree)]
enum DocumentMessage {
Rename { name: String },
} Defensive patterns
Strategy: validation
Prevention
- HierarchicalTree is enum-only; keep it off structs and unions.
- When introducing payload structs, start from a minimal derive list and add what compiles.
- Watch for IDE actions that apply a whole crate's derive set to new types.
When it happens
Trigger: Adding `#[derive(HierarchicalTree)]` to a `struct` or `union`. The match on `input.data` only binds `Data::Enum`.
Common situations: A message type refactored from enum to struct (or vice versa: derive list copied from an enum onto a new struct payload type), or IDE auto-derive inserting the full standard derive list onto every new type.
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
- ExtractField only works on structs
- 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/9fc8a3c653211f5c.
Report an issue: GitHub.