clockworklabs/SpacetimeDB · error
Route paths may contain only {}: {path}
Error message
Route paths may contain only {}: {path} What it means
assert_valid_path rejects route paths containing characters outside the allowed set, which the SDK describes as: ASCII lowercase letters, digits and `-_~/`. Uppercase letters, dots, colons, braces, spaces and any non-ASCII character panic at router construction. Notably this rules out path parameters like "/users/{id}".
Source
Thrown at crates/bindings/src/http.rs:414
fn join_paths(prefix: &str, suffix: &str) -> String {
if prefix == "/" {
return suffix.to_string();
}
if suffix == "/" {
return prefix.to_string();
}
let prefix = prefix.trim_end_matches('/');
let suffix = suffix.trim_start_matches('/');
format!("{prefix}/{suffix}")
}
#[cfg(feature = "unstable")]
fn assert_valid_path(path: &str) {
if !path.is_empty() && !path.starts_with('/') {
panic!("Route paths must start with `/`: {path}");
}
if !path.chars().all(character_is_acceptable_for_route_path) {
panic!(
"Route paths may contain only {}: {path}",
ACCEPTABLE_ROUTE_PATH_CHARS_HUMAN_DESCRIPTION
);
}
}
#[cfg(feature = "unstable")]
fn routes_overlap(a: &RouteSpec, b: &RouteSpec) -> bool {
if a.path != b.path {
return false;
}
matches!(a.method, MethodOrAny::Any) || matches!(b.method, MethodOrAny::Any) || a.method == b.method
}
/// Allows performing HTTP requests via [`HttpClient::send`] and [`HttpClient::get`].
///
/// Access an `HttpClient` from within [procedures](crate::procedure)
/// via [the `http` field of the `ProcedureContext`](crate::ProcedureContext::http).View on GitHub (pinned to 6dee26c6ef)
Solutions
- Lowercase the path and strip unsupported characters; use only a-z, 0-9, '-', '_', '/', '~'.
- Replace path parameters with query parameters (e.g. "/user?id=42") since dynamic segments are not supported.
- Replace dots with '-' (e.g. "/report-json") and pass extensions as query args.
Example fix
// before
let r = Router::new()
.route(Method::GET, "/Users/{id}/Orders.json", h); // panics: '{', '.', uppercase
// after: static lowercase paths, dynamic data via query params
let r = Router::new()
.route(Method::GET, "/user-orders", h); // read id/format from the request query Defensive patterns
Strategy: validation
Validate before calling
fn valid_route_path(p: &str) -> bool {
!p.is_empty()
&& p.starts_with('/')
&& p.chars().all(|c| c.is_ascii_lowercase() || c.is_ascii_digit() || matches!(c, '-' | '_' | '~' | '/'))
}
assert!(valid_route_path("/user-orders")); Prevention
- Use only a-z, 0-9, '-', '_', '~', '/' in route paths.
- No path parameters: pass dynamic values as query parameters instead.
- Add a unit test that validates every route string in your router builder.
When it happens
Trigger: Using path-parameter syntax ("/users/{id}" or "/users/:id") which the router does not support; uppercase path segments ("/Users"); file-extension style paths ("/report.json"); query strings accidentally embedded in the path ("/x?a=b").
Common situations: Porting REST routes from axum/actix that use path params; kebab-case typos introducing dots or uppercase; assuming URL-encoding is permitted in route strings.
Related errors
- Route paths must start with `/`: {path}
- Route paths must start with `/`: {path}
- Route paths may contain only {AcceptableRoutePathCharsHumanD
- Cannot nest router at `{path}`; existing routes overlap with
- Route conflict for `{path}`
AI-assisted analysis of clockworklabs/SpacetimeDB@6dee26c6ef (2026-08-20).
Data as JSON: /api/errors/d3364aa69a8c0255.
Report an issue: GitHub.