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 genericsView on GitHub (pinned to c507b35645)
Solutions
- Change the inherent impl into a trait impl: `impl MessageHandler<ToolMessage, ToolMessageData> for ToolMessageData { … }`.
- Keep inherent helper methods in a separate, unannotated impl block.
- 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
- Annotate only trait impls with #[message_handler_data]; leave inherent impls bare.
- When adding helper methods, create a separate plain impl block.
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
- Expected impl implementation
- Expected MessageHandler trait
- Expected type path
- Unsupported type format
- Failed to parse input type for #[implementation(...)]. Expec
AI-assisted analysis of GraphiteEditor/Graphite@c507b35645 (2026-08-16).
Data as JSON: /api/errors/25ce541108821cfd.
Report an issue: GitHub.