{"id":"8ce3b6976cbfaf87","repo":"tokio-rs/axum","slug":"missing-path-typed-path-foo-bar","errorCode":null,"errorMessage":"Missing path: `#[typed_path(\"/foo/bar\")]`","messagePattern":"Missing path: `#\\[typed_path\\(\"/foo/bar\"\\)\\]`","errorType":"validation","errorClass":"compile_error","httpStatus":null,"severity":"error","filePath":"axum-macros/src/typed_path.rs","lineNumber":26,"sourceCode":"    let ItemStruct {\n        attrs,\n        ident,\n        generics,\n        fields,\n        ..\n    } = item_struct;\n\n    if !generics.params.is_empty() || generics.where_clause.is_some() {\n        return Err(syn::Error::new_spanned(\n            generics,\n            \"`#[derive(TypedPath)]` doesn't support generics\",\n        ));\n    }\n\n    let Attrs { path, rejection } = crate::attr_parsing::parse_attrs(\"typed_path\", attrs)?;\n\n    let path = path.ok_or_else(|| {\n        syn::Error::new(\n            Span::call_site(),\n            \"Missing path: `#[typed_path(\\\"/foo/bar\\\")]`\",\n        )\n    })?;\n\n    let rejection = rejection.map(second);\n\n    match fields {\n        syn::Fields::Named(_) => {\n            let segments = parse_path(&path)?;\n            Ok(expand_named_fields(\n                ident,\n                &path,\n                &segments,\n                rejection.as_ref(),\n            ))\n        }\n        syn::Fields::Unnamed(fields) => {","sourceCodeStart":8,"sourceCodeEnd":44,"githubUrl":"https://github.com/tokio-rs/axum/blob/c9a911b7999de50e9e5023942ca072e9725ae943/axum-macros/src/typed_path.rs#L8-L44","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Add the helper attribute immediately above the struct: `#[typed_path(\"/users/{id}\")]`.","Confirm the attribute name is exactly `typed_path` (snake_case) and the value is a single string literal starting with `/`.","If you intended a route with no captures on a unit struct, supply a static path like `#[typed_path(\"/health\")]`.","If you only wanted serde deserialization of path params, drop `#[derive(TypedPath)]` and use `Path<YourStruct>` directly in the handler."],"exampleFix":"// before\n#[derive(TypedPath, Deserialize)]\nstruct MyPath { id: u32 }\n\n// after\n#[derive(TypedPath, Deserialize)]\n#[typed_path(\"/users/{id}\")]\nstruct MyPath { id: u32 }","handlingStrategy":"validation","validationCode":"// The derive REQUIRES the helper attribute. Add a CI grep to catch missing it:\n//   rg --type rust '#\\[derive\\([^)]*TypedPath' -A 5 | \\\n//     rg -B1 -A4 'struct ' | rg -v 'typed_path\\(' && echo FAIL || true\n//\n// Convention: define a tiny macro_rules! that forces both pieces together:\nmacro_rules! typed_route {\n    ($name:ident, $path:literal, $($body:tt)*) => {\n        #[derive(::axum_macros::TypedPath)]\n        #[typed_path($path)]\n        $($body)*\n        struct $name;\n    };\n}\n// Usage: typed_route!(Health, \"/health\");  // impossible to forget the attribute","typeGuard":"// Compile-time check that TypedPath::PATH is defined (fails if derive was skipped\n// or attribute missing because the impl wouldn't be generated).\nconst _: fn() = || {\n    fn assert_typed_path<T: ::axum_extra::routing::TypedPath>() {}\n    assert_typed_path::<MyPath>();\n    // Also assert the path constant equals what you expect:\n    const EXPECTED: &str = \"/users/{id}\";\n    const _: () = assert!(MyPath::PATH == EXPECTED);\n};","tryCatchPattern":null,"preventionTips":["Always write `#[typed_path(\"...\")]` on the line immediately above `#[derive(TypedPath)]` so the two stay visually paired.","Use the `typed_route!` macro above for unit routes so the attribute cannot be omitted.","Add a `const _: () = assert!(MyPath::PATH == \"/expected\");` test for every typed route to catch missing attributes at compile time.","Run `cargo check` after adding any new `TypedPath` derive; this error is purely compile-time."],"tags":["rust","axum","proc-macro","typed-path","routing","derive","compile-time"],"analyzedSha":"c9a911b7999de50e9e5023942ca072e9725ae943","analyzedAt":"2026-08-06T01:08:56.656Z","schemaVersion":2}