GraphiteEditor/Graphite · error · syn::Error
Expected MessageHandler trait
Error message
Expected MessageHandler trait
What it means
The trait being implemented under `#[message_handler_data]` must literally end in a segment named `MessageHandler` (i.e. `MessageHandler<M, C>`). This error is raised when the last path segment of the trait is a different name, because the macro cannot pull the message and context types from its angle-bracketed arguments.
Source
Thrown at proc-macros/src/message_handler_data_attr.rs:30
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
let type_name = &type_path.path.segments.first().unwrap().ident;
let handler_data_line_number = type_name.span().start().line;
quote! {
#input_itemView on GitHub (pinned to c507b35645)
Solutions
- Make the impl target the real trait: `impl MessageHandler<M, C> for MyHandler { … }`.
- If you aliased the trait (`use x::MessageHandler as MH;`), use the original name in the impl so the segment matches.
- Remove the attribute from impls of unrelated traits — they don't need message-handler registration.
Example fix
// before
#[message_handler_data]
impl SomeOtherTrait for BrushTool { ... }
// after
#[message_handler_data]
impl MessageHandler<BrushMessage, BrushToolMessageData> for BrushTool { ... } Defensive patterns
Strategy: validation
Prevention
- End the trait path with exactly `MessageHandler` in annotated impls; avoid trait aliases in that position.
- Keep unrelated trait impls unannotated.
When it happens
Trigger: Writing `#[message_handler_data] impl SomeOtherTrait for MyHandler { … }`, importing MessageHandler under an alias so the segment name differs, or using a re-exported/renamed trait path whose final segment is not exactly `MessageHandler`.
Common situations: Copy-pasting an impl block from another trait integration, trait aliases or wrapper traits added during a refactor, or namespaced paths like `handlers::MessageHandler` are fine only if the last segment still reads `MessageHandler`.
Related errors
- Expected impl implementation
- Expected trait implementation
- 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/6e8853c0b5d7592e.
Report an issue: GitHub.