GraphiteEditor/Graphite · error · syn::Error
tried to derive TransitiveChild without a #[parent] attribut
Error message
tried to derive TransitiveChild without a #[parent] attribute (on {}) What it means
The `TransitiveChild` derive requires a companion `#[parent(ParentType, expr)]` helper attribute that tells it the parent type and how to navigate from child to parent (used to climb message hierarchies up to a `TopParent`). Deriving it without that attribute is a compile error naming the offending type.
Source
Thrown at proc-macros/src/transitive_child.rs:12
use crate::helper_structs::Pair;
use proc_macro2::{Span, TokenStream};
use syn::{DeriveInput, Expr, Type};
pub fn derive_transitive_child_impl(input_item: TokenStream) -> syn::Result<TokenStream> {
let input = syn::parse2::<DeriveInput>(input_item).unwrap();
let attribute = input
.attrs
.iter()
.find(|a| a.path().is_ident("parent"))
.ok_or_else(|| syn::Error::new(Span::call_site(), format!("tried to derive TransitiveChild without a #[parent] attribute (on {})", input.ident)))?;
let parent_is_top = input.attrs.iter().any(|a| a.path().is_ident("parent_is_top"));
let Pair {
first: parent_type,
second: to_parent,
..
} = attribute.parse_args::<Pair<Type, Expr>>()?;
let top_parent_type: Type = syn::parse_quote! { <#parent_type as TransitiveChild>::TopParent };
let input_type = &input.ident;
let trait_impl = quote::quote! {
impl TransitiveChild for #input_type {
type Parent = #parent_type;
type TopParent = #top_parent_type;
}View on GitHub (pinned to c507b35645)
Solutions
- Add the helper attribute above the derive: `#[parent(ParentType, |c| c.parent)]` — first the parent type, then an expression/closure navigating child→parent.
- For the root of the hierarchy, combine `#[parent(ParentType, expr)] #[parent_is_top]` if that parent is the top.
- Ensure the attribute is spelled exactly `parent` and sits on the same item as the derive.
Example fix
// before
#[derive(TransitiveChild)]
struct LayerNode {
parent: Option<Box<DocumentNode>>,
}
// after
#[parent(DocumentNode, |n| n.parent_as_document())]
#[derive(TransitiveChild)]
struct LayerNode {
parent: Option<Box<DocumentNode>>,
} Defensive patterns
Strategy: validation
Prevention
- Always pair #[derive(TransitiveChild)] with a #[parent(Type, expr)] helper attribute.
- Spell the helper exactly `parent`; `parent_is_top` is only an extra modifier.
- When refactoring hierarchies, grep for `derive(.*TransitiveChild` and check each item still has its #[parent].
When it happens
Trigger: Applying `#[derive(TransitiveChild)]` to a struct or enum with no `#[parent(...)]` attribute present. The `.find(|a| a.path().is_ident("parent"))` returns None. Note `#[parent_is_top]` alone is not enough — it is only a modifier.
Common situations: Adding the derive from an IDE completion that lists it with the standard derives, refactoring that deletes the helper attribute, or writing `#[parent_is_top]` on the root type and forgetting `#[parent]` on an intermediate child. Also: `#[parent]` must be resolvable — if it is stripped by cfg or misspelled, the same error appears.
Related errors
- Failed to parse input type for #[implementation(...)]. Expec
- Expected `->` arrow after input type in #[implementations(..
- Failed to parse output type for #[implementation(...)]. Expe
- Failed to parse node_fn attributes: {e}
- Failed to parse implementations for argument '{name}': {e}
AI-assisted analysis of GraphiteEditor/Graphite@c507b35645 (2026-08-16).
Data as JSON: /api/errors/eeb30ca981a75f28.
Report an issue: GitHub.