DioxusLabs/dioxus · error · syn::Error

Cannot have multiple query parameters when one is a catch-al

Error message

Cannot have multiple query parameters when one is a catch-all

What it means

A dioxus-fullstack route string may declare several query parameters, but at most one of them may be a catch-all (`:name` or `{name}` syntax in the query section). A catch-all consumes the remaining query pairs, so mixing it with other query params is ambiguous and rejected at compile time (packages/fullstack-macro/src/lib.rs:714).

Source

Thrown at packages/fullstack-macro/src/lib.rs:717

                    param.binding.span(),
                    format!(
                        "query parameter `{}` not found in function arguments",
                        param.binding
                    ),
                )
            })?;
            query_params.push(QueryParam {
                binding: ident,
                name: param.name,
                catch_all: param.catch_all,
                ty: ty.0,
                arg_idx: ty.1,
            });
        }

        // Disallow multiple query params if one is a catch-all
        if query_params.iter().any(|param| param.catch_all) && query_params.len() > 1 {
            return Err(syn::Error::new(
                Span::call_site(),
                "Cannot have multiple query parameters when one is a catch-all",
            ));
        }

        if let Some(options) = route.oapi_options.as_mut() {
            options.merge_with_fn(function)
        }

        let method = match (method_from_macro, route.method) {
            (Some(method), None) => method,
            (None, Some(method)) => method,
            (Some(_), Some(_)) => {
                return Err(syn::Error::new(
                    Span::call_site(),
                    "HTTP method specified both in macro and in attribute",
                ));
            }

View on GitHub (pinned to 393d190a80)

Solutions

  1. Keep only the catch-all and fold all query data into it, e.g. `#[route(GET, "/list?:filters")]` with `filters: HashMap<String, String>`.
  2. Or drop the catch-all and list every param explicitly: `/list?page&per_page`.
  3. Remember plain query params are written bare (`page`) or as `url_name=binding`; `{name}`/`:name` mean catch-all — switch the syntax if you did not intend a catch-all.

Example fix

// before
#[route(GET, "/list?page&:filters")]
async fn list(page: usize, filters: HashMap<String, String>) { ... }

// after
#[route(GET, "/list?filters")]
async fn list(filters: HashMap<String, String>) { ... }
Defensive patterns

Strategy: validation

Validate before calling

def check_query(route: str):
    q = route.split('?', 1)[1] if '?' in route else ''
    segs = [s for s in q.split('&') if s]
    catchalls = [s for s in segs if s.startswith(':') or (s.startswith('{') and s.endswith('}'))]
    assert not (catchalls and len(segs) > 1), f'catch-all mixed with other query params in {route!r}'

Prevention

When it happens

Trigger: `#[route(GET, "/list?page&:filters")]` — one normal param `page` plus catch-all `filters`; likewise `"/list?page&{filters}"`. Any route string where `query.split('&')` yields 2+ entries and at least one starts with `:` or is wrapped in `{}`.

Common situations: Wanting pagination plus an open-ended filter bag in one endpoint; migrating an axum handler that deserialized a struct with `HashMap<String, String>` flatten alongside scalar params; misusing `{name}` (intended for catch-all) instead of plain `name` for a normal query param.

Related errors


AI-assisted analysis of DioxusLabs/dioxus@393d190a80 (2026-08-16). Data as JSON: /api/errors/c6356c302db75f6f. Report an issue: GitHub.