{"record":{"id":"8ed607f44b7ac622","repo":"neondatabase/neon","slug":"no-param-name-specified-in-path-param","errorCode":null,"errorMessage":"no {param_name} specified in path param","messagePattern":"no (.+?) specified in path param","errorType":"http","errorClass":"ApiError","httpStatus":400,"severity":"error","filePath":"libs/http-utils/src/request.rs","lineNumber":18,"sourceCode":"use core::fmt;\nuse std::borrow::Cow;\nuse std::str::FromStr;\n\nuse anyhow::anyhow;\nuse hyper::body::HttpBody;\nuse hyper::{Body, Request};\nuse routerify::ext::RequestExt;\n\nuse super::error::ApiError;\n\npub fn get_request_param<'a>(\n    request: &'a Request<Body>,\n    param_name: &str,\n) -> Result<&'a str, ApiError> {\n    match request.param(param_name) {\n        Some(arg) => Ok(arg),\n        None => Err(ApiError::BadRequest(anyhow!(\n            \"no {param_name} specified in path param\",\n        ))),\n    }\n}\n\npub fn parse_request_param<T: FromStr>(\n    request: &Request<Body>,\n    param_name: &str,\n) -> Result<T, ApiError> {\n    match get_request_param(request, param_name)?.parse() {\n        Ok(v) => Ok(v),\n        Err(_) => Err(ApiError::BadRequest(anyhow!(\n            \"failed to parse {param_name}\",\n        ))),\n    }\n}\n\npub fn get_query_param<'a>(","sourceCodeStart":1,"sourceCodeEnd":36,"githubUrl":"https://github.com/neondatabase/neon/blob/8f60b04da47ffefe0e52bda2440134b42874eb75/libs/http-utils/src/request.rs#L1-L36","documentation":"Returned as HTTP 400 BadRequest by get_request_param in neon's http-utils when routerify's request.param(param_name) yields None, i.e. the named path parameter was not captured for this request. Because routerify only populates params for patterns that matched, in practice this fires when the handler is invoked on a route whose pattern does not actually define that :param (a route-wiring bug), rather than from a client supplying a wrong value.","triggerScenarios":"A handler registered on /v1/tenant calls get_request_param(req, \"tenant_id\") while the route is defined as /v1/tenants (no :tenant_id segment); or a route refactor renamed the pattern segment (e.g. :tenantId vs :tenant_id) so lookup by the old name misses.","commonSituations":"Route registration refactors where the pattern and the param name in the handler drift apart; copy-pasting a handler to a new route that lacks the segment; routerify middleware re-creating requests without params; adding a new endpoint and forgetting the path parameter in the route string.","solutions":["Compare the route pattern string with the param_name passed to get_request_param — they must match exactly, including the leading colon segment name","Fix the route definition (or the handler's param name) so the pattern declares :<param_name>","Add a route-level test that hits the endpoint and asserts the param resolves"],"exampleFix":"// before\nRouter::new()\n    .get(\"/v1/tenant\", tenant_handler)  // handler calls get_request_param(req, \"tenant_id\")\n\n// after\nRouter::new()\n    .get(\"/v1/tenant/:tenant_id\", tenant_handler)","handlingStrategy":"type-guard","validationCode":"// Add a route test that fails when the pattern loses its param:\n#[tokio::test]\nasync fn tenant_route_has_param() {\n    let resp = router_get(\"/v1/tenant/abc\").await;\n    assert_ne!(resp.status(), 400, \"tenant_id param missing from route pattern\");\n}","typeGuard":"// In middleware, fail loudly on handlers requesting params the pattern lacks:\nfn route_defines_param(route: &str, name: &str) -> bool {\n    route.split('/').any(|seg| seg == &format!(\":{name}\"))\n}","tryCatchPattern":null,"preventionTips":["Derive handler param names from the route pattern constants instead of duplicating strings","Prefer compile-time route builders that force the pattern and the param name to match","Add one integration test per route asserting path params resolve"],"tags":["neon","http-utils","routing","path-param","routerify"],"backgroundTag":"missing-path-parameter","analyzedSha":"8f60b04da47ffefe0e52bda2440134b42874eb75","analyzedAt":"2026-08-16T23:39:28.135Z","schemaVersion":2},"datasetVersion":"2026-08-17T04:17:16.089Z"}