tokio-rs/axum · error · syn::Error

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

Error message

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

What it means

Thrown by #[derive(TypedPath)] (typed_path.rs:26). The derive parses attributes named typed_path via parse_attrs; the Attrs::parse parser only fills the path field when it peeks a LitStr. If after parsing, path is None (no #[typed_path("...")] attribute present, or only a rejection(...) sub-attribute was given with no string literal), path.ok_or_else emits this error. (Generics, or a non-struct item, produce different errors upstream.)

Solutions

  1. Add the attribute with a route literal: #[typed_path("/your/route")].
  2. Make sure the route starts with '/' (a missing leading slash raises a separate error).
  3. If you only want a rejection override, still include the path: #[typed_path("/foo", rejection(MyRejection))].

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

// Safe invocation pattern: every TypedPath derive needs a `#[typed_path("...")]` literal.
#[derive(TypedPath, Deserialize)]
#[typed_path("/users/{id}")] // route literal is mandatory and must start with '/'
struct UsersShow {
    id: u32,
}

// With a custom rejection, the path literal is still required:
#[derive(TypedPath, Deserialize)]
#[typed_path("/users/{id}", rejection(MyRejection))]
struct UsersShow {
    id: u32,
}

Prevention

When it happens

Trigger: #[derive(TypedPath)] struct MyPath { ... } with no #[typed_path("...")] attribute. Also triggered by #[typed_path(rejection(Foo))] without a path string, since the rejection keyword does not set path.

Common situations: Forgetting the typed_path attribute entirely. Misspelling it (e.g. #[path("...")]). Adding #[derive(TypedPath)] alongside other derives and assuming the route comes from elsewhere (e.g. from an axum::Router::route call). Only supplying a rejection type and omitting the route literal.

Related errors


AI-assisted analysis of tokio-rs/axum@151cd5c123 (2026-08-11). Data as JSON: /api/errors/17c6f51600bb637a. Report an issue: GitHub.

Appendix: 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 151cd5c123)