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

  1. Add the helper attribute above the derive: `#[parent(ParentType, |c| c.parent)]` — first the parent type, then an expression/closure navigating child→parent.
  2. For the root of the hierarchy, combine `#[parent(ParentType, expr)] #[parent_is_top]` if that parent is the top.
  3. 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

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


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