{"record":{"id":"d76136f0cd989915","repo":"JuliusBrussee/caveman","slug":"azure-request-has-duplicate-api-version-values","errorCode":null,"errorMessage":"azure request has duplicate api-version values","messagePattern":"azure request has duplicate api-version values","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"proxy/providers/azureopenai/azure_routing.go","lineNumber":42,"sourceCode":"\t\"2025-04-01-preview\",\n\t\"preview\",\n\t\"latest\",\n}\n\n// ResolveUpstreamURL validates either the legacy deployment route or the\n// current Foundry Models v1 inference route before resolving upstream.\nfunc (a Adapter) ResolveUpstreamURL(ctx context.Context, req *http.Request, route providers.RouteContext) (*url.URL, error) {\n\tif err := validateAzureRequest(req.URL); err != nil {\n\t\treturn nil, err\n\t}\n\treturn a.Base.ResolveUpstreamURL(ctx, req, route)\n}\n\nfunc validateAzureRequest(u *url.URL) error {\n\tif foundryV1InferenceRoute(u.Path) {\n\t\tversions := u.Query()[\"api-version\"]\n\t\tif len(versions) > 1 {\n\t\t\treturn fmt.Errorf(\"azure request has duplicate api-version values\")\n\t\t}\n\t\tif len(versions) == 1 && versions[0] != \"v1\" && versions[0] != \"preview\" {\n\t\t\treturn fmt.Errorf(\"azure Foundry api-version %q is not supported\", versions[0])\n\t\t}\n\t\treturn nil\n\t}\n\tif !legacyChatCompletionsRoute(u.Path) {\n\t\treturn fmt.Errorf(\"azure legacy inference path %q is not supported\", u.Path)\n\t}\n\tversions := u.Query()[\"api-version\"]\n\tif len(versions) > 1 {\n\t\treturn fmt.Errorf(\"azure request has duplicate api-version values\")\n\t}\n\tversion := \"\"\n\tif len(versions) == 1 {\n\t\tversion = versions[0]\n\t}\n\tif version == \"\" {","sourceCodeStart":24,"sourceCodeEnd":60,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/3ee70a102609e550bd2e68004bf5990a9341c851/proxy/providers/azureopenai/azure_routing.go#L24-L60","documentation":"validateAzureRequest inspects Azure Foundry v1 inference routes and enforces at most one api-version query parameter, restricted to \"v1\" or \"preview\". Duplicate api-version values (repeated query keys) are ambiguous, so the request is rejected before building the upstream URL.","triggerScenarios":"Building an Azure OpenAI URL whose query string contains api-version twice, e.g. manually concatenated \"...?api-version=v1&api-version=preview\" or a template + override both appending api-version.","commonSituations":"String-concatenating query params onto a URL that already had api-version; deploying a route/template where a client SDK appends api-version on top of a configured one; copy-paste of example URLs retaining a second api-version.","solutions":["Remove duplicate api-version params so exactly one remains (\"v1\" or \"preview\" for Foundry routes)","Fix URL-building code to append api-version only if not already present","Use url.Values to construct the query string instead of string concatenation"],"exampleFix":"// before\nu := base + \"?api-version=v1\"\nu += \"&api-version=preview\"\n// after\nq := u.Query()\nif q.Get(\"api-version\") == \"\" {\n\tq.Set(\"api-version\", \"v1\")\n}\nu.RawQuery = q.Encode()","handlingStrategy":"validation","validationCode":"q := u.Query()\nif len(q[\"api-version\"]) > 1 {\n\treturn errors.New(\"api-version may appear at most once\")\n}","typeGuard":null,"tryCatchPattern":"u, err := adapter.ResolveUpstreamURL(ctx, req, route)\nif err != nil && strings.Contains(err.Error(), \"duplicate api-version\") {\n\t// return 400 with guidance to dedupe query params\n}","preventionTips":["Build query strings with url.Values, never raw concatenation","Check for existing params before appending api-version","Review URL templates for doubled query keys"],"tags":["azure","query-parameters","validation"],"backgroundTag":"invalid-query-parameter","analyzedSha":"3ee70a102609e550bd2e68004bf5990a9341c851","analyzedAt":"2026-09-20T15:53:39.229Z","contentChangedAt":"2026-09-20T15:53:39.229Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}