GraphiteEditor/Graphite · error · syn::Error

Expected type path

Error message

Expected type path

What it means

Inside `#[message_handler_data]`, when the context type argument `C` of `MessageHandler<M, C>` is a reference (`&T` / `&'a mut T`), the referenced element must itself be a plain type path so the macro can take its identifier for line-number lookup and `field_types()`/`path()` calls. A reference to a tuple, slice, or other non-path type fails here.

Source

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

											MessageData::new(format!("{}", stringify!(#input_type)), #input_type::field_types(), #input_type::path(), #input_type::line_number())

										}
									}
								}
							}
							syn::Type::Tuple(_) => quote! {
								#input_item
								impl #message_type {
										pub fn message_handler_str() -> MessageData {
											MessageData::new(format!("{}", stringify!(#input_type)), #input_type::field_types(), #input_type::path(), #input_type::line_number())
										}
									}
							},
							syn::Type::Reference(type_reference) => {
								let message_type = call_site_ident(format!("{input_type}Message"));
								let type_ident = match &*type_reference.elem {
									syn::Type::Path(type_path) => &type_path.path.segments.first().unwrap().ident,
									_ => return Err(syn::Error::new(type_reference.elem.span(), "Expected type path")),
								};

								let type_line_number = type_ident.span().start().line;

								let tr = clean_rust_type_syntax(type_reference.to_token_stream().to_string());
								quote! {
									#input_item
									impl #message_type {
										pub fn message_handler_data_str() -> MessageData {
											MessageData::new(format!("{}", #tr), #type_ident::field_types(), #type_ident::path(), #type_ident::line_number())
										}

										pub fn message_handler_str() -> MessageData {
											MessageData::new(format!("{}", stringify!(#input_type)), #input_type::field_types(), #input_type::path(), #input_type::line_number())

										}
									}
								}

View on GitHub (pinned to c507b35645)

Solutions

  1. Use a named struct (or the conventional ToolMessageData type) as the referenced context: `&ToolMessageData`.
  2. Define `struct Ctx(u8, u8);` and use `&Ctx` so the inner element is a path.
  3. If the tuple form was intentional, use a plain tuple type `C = (u8, u8)` rather than a reference to one — the macro has a dedicated arm for tuple context types.

Example fix

// before
#[message_handler_data]
impl MessageHandler<BrushMessage, &(u64, String)> for BrushTool { ... }

// after
struct BrushContext {
	layer: u64,
	name: String,
}
#[message_handler_data]
impl MessageHandler<BrushMessage, &BrushContext> for BrushTool { ... }
Defensive patterns

Strategy: validation

Prevention

When it happens

Trigger: Writing `impl MessageHandler<Msg, &(u8, u8)> for …`, `impl MessageHandler<Msg, &[Tool]…>` style reference-to-non-path context types. The match binds `Type::Reference` but the inner `elem` is not `Type::Path`.

Common situations: Changing a context parameter from a named data struct to an ad-hoc tuple or slice reference to 'simplify' a handler signature, especially for tools that previously shared a single context struct.

Related errors


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