{"record":{"id":"56f9f8ef8c773737","repo":"reactiveui/refit","slug":"url-relativepathtemplate-has-parameter-key","errorCode":null,"errorMessage":"URL {relativePathTemplate} has parameter {{{key}}}, but no method parameter matches","messagePattern":"URL (.+?) has parameter (.+?)\\}\\}, but no method parameter matches","errorType":"validation","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"src/Refit/GeneratedRequestRunner.cs","lineNumber":697,"sourceCode":"        if (allowUnmatchedParameter)\n        {\n            return path;\n        }\n\n        var i = path.IndexOf('{');\n        if (i < 0)\n        {\n            return path;\n        }\n\n        var j = path.AsSpan(i).IndexOfAny('}', '/');\n        if (j < 0 || path[j += i] != '}')\n        {\n            return path;\n        }\n\n        var key = path[(i + 1)..j];\n        throw new ArgumentException(\n            $\"URL {relativePathTemplate} has parameter {{{key}}}, but no method parameter matches\");\n    }\n\n    /// <summary>Rejects a no-leading-slash path under legacy resolution, matching the reflection request builder.</summary>\n    /// <param name=\"relativePath\">The resolved relative request path.</param>\n    /// <exception cref=\"ArgumentException\">The path is non-empty and does not start with '/'.</exception>\n    internal static void RequireLeadingSlashUnderLegacy(string relativePath)\n    {\n        if (relativePath.Length == 0 || relativePath[0] == '/')\n        {\n            return;\n        }\n\n        throw new ArgumentException(\n            $\"URL path {relativePath} must start with '/' and be of the form '/foo/bar/baz'\");\n    }\n\n    /// <summary>Builds the message describing an invalid <c>[Url]</c> parameter value.</summary>","sourceCodeStart":679,"sourceCodeEnd":715,"githubUrl":"https://github.com/reactiveui/refit/blob/b455f65ecc4c97d092317e349cb775f9cfc6bcdf/src/Refit/GeneratedRequestRunner.cs#L679-L715","documentation":"Thrown when a route template contains a {key} placeholder that no method parameter supplies. After locating a '{' and its matching '}', the builder extracts the key and throws an ArgumentException naming the unmatched placeholder and the template. It is a design-time contract violation surfaced at request build time.","triggerScenarios":"An interface method declares a route like [Get(\"/items/{id}/sub/{subId}\")] but only has an 'id' parameter (subId missing), or a placeholder name has a typo differing from the parameter name. Each template token must correspond to a parameter passed via the uriParams collection.","commonSituations":"Refactoring a route and forgetting to add/remove the matching parameter; copy-paste typos between the template placeholder and the parameter name; renaming a parameter without updating the template; relying on a parameter that was conditionally compiled out.","solutions":["Add a method parameter whose name matches the {key} in the route template exactly","Fix the typo so the template placeholder and parameter name agree (C# identifiers are case-sensitive)","Remove the unused {key} from the route template if it is no longer needed","If unmatched placeholders are intentional, set allowUnmatchedParameter so the builder skips them instead of throwing"],"exampleFix":"// before\n[Get(\"/items/{id}/children/{childId}\")]\nTask<IList<Child>> GetChildrenAsync(long id);\n// childId has no parameter => throws\n\n// after\n[Get(\"/items/{id}/children/{childId}\")]\nTask<IList<Child>> GetChildrenAsync(long id, long childId);","handlingStrategy":"validation","validationCode":"// Design-time: ensure every {key} in a route template has a matching parameter.\nstatic IEnumerable<string> UnmatchedPlaceholders(string template, IEnumerable<string> paramNames)\n{\n    var nameSet = paramNames.ToHashSet();\n    var matches = System.Text.RegularExpressions.Regex.Matches(template, @\"\\{(\\w+)\\}\");\n    foreach (System.Text.RegularExpressions.Match m in matches)\n        if (!nameSet.Contains(m.Groups[1].Value))\n            yield return m.Groups[1].Value;\n}","typeGuard":null,"tryCatchPattern":"try { await api.GetChildrenAsync(id, childId); }\ncatch (ArgumentException ex) when (ex.Message.Contains(\"but no method parameter matches\"))\n{\n    // interface/template mismatch - fix the route or add the parameter\n}","preventionTips":["Treat every {key} in a route template as requiring an identically named parameter","Add a build-time test that scans all interface routes for unmatched placeholders","Rename parameters and template placeholders together to keep them in sync","Use allowUnmatchedParameter only when unmatched placeholders are intentional"],"tags":["routing","template","url-parameter","argument","design-contract"],"backgroundTag":null,"analyzedSha":"b455f65ecc4c97d092317e349cb775f9cfc6bcdf","analyzedAt":"2026-08-13T21:20:57.878Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}