GraphiteEditor/Graphite · error · syn::Error

Expected trait implementation

Error message

Expected trait implementation

What it means

`#[message_handler_data]` must annotate a trait implementation, not an inherent impl. The macro reads the trait path from the impl block to extract the `MessageHandler<M, C>` generic arguments and generate the `MessageData` registration; an inherent `impl MyType { … }` has no trait to read, so the derive aborts.

Source

Thrown at proc-macros/src/message_handler_data_attr.rs:24

pub fn message_handler_data_attr_impl(attr: TokenStream, input_item: TokenStream) -> syn::Result<TokenStream> {
	// Parse the input as an impl block
	let impl_block = parse2::<ItemImpl>(input_item.clone())?;

	let self_ty = &impl_block.self_ty;

	let path = match &**self_ty {
		Type::Path(path) => &path.path,
		_ => return Err(syn::Error::new(Span::call_site(), "Expected impl implementation")),
	};

	let input_type = path.segments.last().map(|s| &s.ident).unwrap();

	let handler_line_number = input_type.span().start().line;

	// Extract the message type from the trait path
	let trait_path = match &impl_block.trait_ {
		Some((_, path, _)) => path,
		None => return Err(syn::Error::new(Span::call_site(), "Expected trait implementation")),
	};

	// Get the trait generics (should be MessageHandler<M, C>)
	if let Some(segment) = trait_path.segments.last() {
		if segment.ident != "MessageHandler" {
			return Err(syn::Error::new(segment.ident.span(), "Expected MessageHandler trait"));
		}
		if let syn::PathArguments::AngleBracketed(args) = &segment.arguments {
			if args.args.len() >= 2 {
				// Extract the message type (M) and context struct type (C) from the trait params
				let message_type = &args.args[0];
				let data_type = &args.args[1];

				let impl_item = match data_type {
					syn::GenericArgument::Type(t) => {
						match t {
							syn::Type::Path(type_path) if !type_path.path.segments.is_empty() => {
								// Get just the base identifier (ToolMessageData) without generics

View on GitHub (pinned to c507b35645)

Solutions

  1. Change the inherent impl into a trait impl: `impl MessageHandler<ToolMessage, ToolMessageData> for ToolMessageData { … }`.
  2. Keep inherent helper methods in a separate, unannotated impl block.
  3. Verify the trait generics are present; the macro expects MessageHandler<M, C> with two arguments.

Example fix

// before
#[message_handler_data]
impl ToolMessageData {
	fn tool_name(&self) -> String { ... }
}

// after
impl ToolMessageData {
	fn tool_name(&self) -> String { ... }
}

#[message_handler_data]
impl MessageHandler<ToolMessage, ToolMessageData> for ToolMessageData {
	fn process_message(&mut self, message: ToolMessage) { ... }
}
Defensive patterns

Strategy: validation

Prevention

When it happens

Trigger: Applying the attribute to `impl ToolMessageData { … }` or any impl without a `for` clause / trait path. The match on `impl_block.trait_` returns None and errors.

Common situations: Adding helper methods to a handler struct and pasting the attribute on the wrong impl block, or annotating every impl in a file mechanically during integration of the message-handler system.

Related errors


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