JuliusBrussee/caveman · error

azure request has duplicate api-version values

Error message

azure request has duplicate api-version values

What it means

On the Foundry Models v1 inference routes (/openai/v1/chat/completions, /openai/v1/responses), validateAzureRequest reads all api-version query parameters and rejects the request if more than one is present. Duplicate query keys make version selection ambiguous, so the proxy refuses rather than pick one. This guard runs in ResolveUpstreamURL before any upstream dial.

Source

Thrown at proxy/providers/azureopenai/azure_routing.go:42

	"2025-04-01-preview",
	"preview",
	"latest",
}

// ResolveUpstreamURL validates either the legacy deployment route or the
// current Foundry Models v1 inference route before resolving upstream.
func (a Adapter) ResolveUpstreamURL(ctx context.Context, req *http.Request, route providers.RouteContext) (*url.URL, error) {
	if err := validateAzureRequest(req.URL); err != nil {
		return nil, err
	}
	return a.Base.ResolveUpstreamURL(ctx, req, route)
}

func validateAzureRequest(u *url.URL) error {
	if foundryV1InferenceRoute(u.Path) {
		versions := u.Query()["api-version"]
		if len(versions) > 1 {
			return fmt.Errorf("azure request has duplicate api-version values")
		}
		if len(versions) == 1 && versions[0] != "v1" && versions[0] != "preview" {
			return fmt.Errorf("azure Foundry api-version %q is not supported", versions[0])
		}
		return nil
	}
	if !legacyChatCompletionsRoute(u.Path) {
		return fmt.Errorf("azure legacy inference path %q is not supported", u.Path)
	}
	versions := u.Query()["api-version"]
	if len(versions) > 1 {
		return fmt.Errorf("azure request has duplicate api-version values")
	}
	version := ""
	if len(versions) == 1 {
		version = versions[0]
	}
	if version == "" {

View on GitHub (pinned to 27d5a3981a)

Solutions

  1. Send exactly one api-version (for Foundry v1 routes: 'v1' or 'preview').
  2. Audit the client for double-appending: disable the SDK's automatic api-version or remove your manual query parameter.
  3. Build URLs with a params map (key set once) instead of string concatenation.

Example fix

# before
curl "$PROXY/azure/openai/v1/chat/completions?api-version=v1&api-version=preview"

# after
curl "$PROXY/azure/openai/v1/chat/completions?api-version=v1"
Defensive patterns

Strategy: validation

Validate before calling

vals := req.URL.Query()["api-version"]
if len(vals) > 1 {
    return fmt.Errorf("duplicate api-version values %v; send exactly one", vals)
}

Type guard

func hasSingleAPIVersion(u *url.URL) bool {
    return len(u.Query()["api-version"]) <= 1
}

Try / catch

if err := validateAzureRequest(req.URL); err != nil {
    if strings.Contains(err.Error(), "duplicate api-version") {
        http.Error(w, "send exactly one api-version query parameter", http.StatusBadRequest)
        return
    }
    http.Error(w, err.Error(), http.StatusBadRequest)
}

Prevention

When it happens

Trigger: A URL like /azure/openai/v1/chat/completions?api-version=v1&api-version=preview — usually caused by a client SDK appending api-version while the caller also set it, or a URL-builder appending the parameter twice.

Common situations: Combining an SDK that auto-appends api-version with hand-added query params; retry/rewrite middleware that appends the param without checking; string concatenation building URLs in scripts.

Related errors


AI-assisted analysis of JuliusBrussee/caveman@27d5a3981a (2026-08-15). Data as JSON: /api/errors/d76136f0cd989915. Report an issue: GitHub.