DioxusLabs/dioxus · error · syn::Error
wildcard path param must be the last path param
Error message
wildcard path param must be the last path param
What it means
A wildcard path segment written as `*name` (PathParam::WildCard) only matches 'the rest of the path', so it is only legal as the final segment. RouteParser::new iterates segments and raises this error for any WildCard at index != last (packages/fullstack-macro/src/lib.rs:999-1009).
Source
Thrown at packages/fullstack-macro/src/lib.rs:1004
return Err(syn::Error::new(span, "expected path to start with '/'"));
}
let path = path.strip_prefix('/').unwrap();
let mut path_params = Vec::new();
for path_param in path.split('/') {
path_params.push((
Slash(span),
PathParam::new(path_param, span, Box::new(parse_quote!(())))?,
));
}
let path_param_len = path_params.len();
for (i, (_slash, path_param)) in path_params.iter().enumerate() {
match path_param {
PathParam::WildCard(_, _, _, _, _, _) => {
if i != path_param_len - 1 {
return Err(syn::Error::new(
span,
"wildcard path param must be the last path param",
));
}
}
PathParam::Capture(_, _, _, _, _) => (),
PathParam::Static(lit) => {
if lit.value() == "*" && i != path_param_len - 1 {
return Err(syn::Error::new(
span,
"wildcard path param must be the last path param",
));
}
}
}
}
let mut query_params = Vec::new();View on GitHub (pinned to 393d190a80)
Solutions
- Move the wildcard to the end: `/files/{path}/meta` won't work either — instead capture per-segment with `{path}` (single segment) or restructure to `/files/meta/*rest`.
- If you need 'one segment anywhere', use a `{name}` capture and parse it yourself.
- If you truly need prefix-style matching, register separate routes per prefix and keep each wildcard last.
Example fix
// before
#[route(GET, "/api/*version/users")]
async fn users(version: Vec<String>) { ... }
// after
#[route(GET, "/api/{version}/users")]
async fn users(version: String) { ... } Defensive patterns
Strategy: validation
Validate before calling
fn validate_route(route: &str) -> Result<(), String> {
let path = route.split('?').next().unwrap().trim_start_matches('/');
let segs: Vec<&str> = path.split('/').collect();
for (i, seg) in segs.iter().enumerate() {
if seg.starts_with('*') && i != segs.len() - 1 {
return Err(format!("wildcard must be last segment: {route}"));
}
}
Ok(())
} Prevention
- Design URLs so catch-alls only ever terminate the path.
- For 'one segment anywhere' semantics use {name} captures, not *.
When it happens
Trigger: `#[route(GET, "/files/*path/meta")]` — segments after the wildcard; nesting a wildcard mid-path hoping for glob behavior; converting an axum `{*path}/tail` route where axum itself would reject it too.
Common situations: Assuming `*` acts like a shell glob that can match one segment in the middle; refactoring `/a/*rest` to `/a/*rest/b` and expecting it to still compile; designing URLs like `/api/*version/users`.
Related errors
- path parameter `{}` not found in function arguments
- expected path param to be wrapped in curly braces
- Use `api_route` instead of `route` to use OpenAPI options
- query parameter `{}` not found in function arguments
- Cannot have multiple query parameters when one is a catch-al
AI-assisted analysis of DioxusLabs/dioxus@393d190a80 (2026-08-16).
Data as JSON: /api/errors/d708654a384b28fd.
Report an issue: GitHub.