tokio-rs/axum · error · compile_error

Missing path: `#[typed_path("/foo/bar")]`

Error message

Missing path: `#[typed_path("/foo/bar")]`

What it means

Thrown by `#[derive(TypedPath)]` when the struct has no `#[typed_path("...")]` attribute supplying the route template. `TypedPath` requires a `const PATH: &str` (see the generated `impl ::axum_extra::routing::TypedPath` at typed_path.rs:112), and the macro has nothing to put there, so at line 25 it converts `None` into this error. The message text is taken verbatim from the `ok_or_else` at line 25-30.

Source

Thrown at axum-macros/src/typed_path.rs:26

    let ItemStruct {
        attrs,
        ident,
        generics,
        fields,
        ..
    } = item_struct;

    if !generics.params.is_empty() || generics.where_clause.is_some() {
        return Err(syn::Error::new_spanned(
            generics,
            "`#[derive(TypedPath)]` doesn't support generics",
        ));
    }

    let Attrs { path, rejection } = crate::attr_parsing::parse_attrs("typed_path", attrs)?;

    let path = path.ok_or_else(|| {
        syn::Error::new(
            Span::call_site(),
            "Missing path: `#[typed_path(\"/foo/bar\")]`",
        )
    })?;

    let rejection = rejection.map(second);

    match fields {
        syn::Fields::Named(_) => {
            let segments = parse_path(&path)?;
            Ok(expand_named_fields(
                ident,
                &path,
                &segments,
                rejection.as_ref(),
            ))
        }
        syn::Fields::Unnamed(fields) => {

View on GitHub (pinned to c9a911b799)

Solutions

  1. Add the helper attribute immediately above the struct: `#[typed_path("/users/{id}")]`.
  2. Confirm the attribute name is exactly `typed_path` (snake_case) and the value is a single string literal starting with `/`.
  3. If you intended a route with no captures on a unit struct, supply a static path like `#[typed_path("/health")]`.
  4. If you only wanted serde deserialization of path params, drop `#[derive(TypedPath)]` and use `Path<YourStruct>` directly in the handler.

Example fix

// before
#[derive(TypedPath, Deserialize)]
struct MyPath { id: u32 }

// after
#[derive(TypedPath, Deserialize)]
#[typed_path("/users/{id}")]
struct MyPath { id: u32 }
Defensive patterns

Strategy: validation

Validate before calling

// The derive REQUIRES the helper attribute. Add a CI grep to catch missing it:
//   rg --type rust '#\[derive\([^)]*TypedPath' -A 5 | \
//     rg -B1 -A4 'struct ' | rg -v 'typed_path\(' && echo FAIL || true
//
// Convention: define a tiny macro_rules! that forces both pieces together:
macro_rules! typed_route {
    ($name:ident, $path:literal, $($body:tt)*) => {
        #[derive(::axum_macros::TypedPath)]
        #[typed_path($path)]
        $($body)*
        struct $name;
    };
}
// Usage: typed_route!(Health, "/health");  // impossible to forget the attribute

Type guard

// Compile-time check that TypedPath::PATH is defined (fails if derive was skipped
// or attribute missing because the impl wouldn't be generated).
const _: fn() = || {
    fn assert_typed_path<T: ::axum_extra::routing::TypedPath>() {}
    assert_typed_path::<MyPath>();
    // Also assert the path constant equals what you expect:
    const EXPECTED: &str = "/users/{id}";
    const _: () = assert!(MyPath::PATH == EXPECTED);
};

Prevention

When it happens

Trigger: Annotated a struct with `#[derive(TypedPath)]` (or `#[axum_macros::TypedPath]`) but forgot the accompanying `#[typed_path("/some/route")]` helper attribute. The parse loop at typed_path.rs:62-81 leaves `path = None`, and the `path.ok_or_else(...)` at line 25 produces the compile error before any field/generation code runs.

Common situations: First-time use of `TypedPath` where the developer assumes the derive alone is sufficient (as it is for many serde/clone derives). Renaming or deleting the helper attribute during a refactor. Splitting attribute lists across macros (e.g. `#[derive(Deserialize, TypedPath)]` with only `#[serde(...)]` present). Upgrading axum-extra and missing the migration note that the path attribute is mandatory.

Related errors


AI-assisted analysis of tokio-rs/axum@c9a911b799 (2026-08-06). Data as JSON: /data/errors/8ce3b6976cbfaf87.json. Report an issue: GitHub.