JuliusBrussee/caveman · error
compat request URL is missing
Error message
compat request URL is missing
What it means
ResolveUpstreamURL in the OpenAI-compatible adapter requires an *http.Request with a non-nil URL to compute the upstream target. If either is nil, there is nothing to resolve and the adapter fails closed rather than guessing. This is an internal contract check guarding the proxy request path.
Solutions
- Ensure the request passed to ResolveUpstreamURL was created via http.NewRequest and that its error return was checked
- Set req.URL explicitly before calling the adapter (req.URL = parsedURL)
- Log the error from http.NewRequest instead of discarding it
- In tests, use httptest.NewRequest which always sets a URL
Example fix
// before
req, _ := http.NewRequestWithContext(ctx, "POST", rawURL, body)
url, err := adapter.ResolveUpstreamURL(ctx, req, routeCtx)
// after
req, err := http.NewRequestWithContext(ctx, "POST", rawURL, body)
if err != nil {
return err
}
url, err := adapter.ResolveUpstreamURL(ctx, req, routeCtx) Defensive patterns
Strategy: try-catch
Validate before calling
if req == nil || req.URL == nil {
return fmt.Errorf("request must have a URL before resolving upstream")
} Type guard
func hasURL(req *http.Request) bool { return req != nil && req.URL != nil } Try / catch
u, err := adapter.ResolveUpstreamURL(ctx, req, routeCtx)
if err != nil {
if strings.Contains(err.Error(), "request URL is missing") {
// rebuild the request via http.NewRequest and retry once
}
return err
} Prevention
- Always create requests with http.NewRequest and check its error
- Never pass nil requests into adapter code paths
- Use httptest.NewRequest in tests
When it happens
Trigger: Calling ResolveUpstreamURL with a nil *http.Request, or with a request constructed without a URL (e.g. http.NewRequest returned an error that was ignored, or a hand-built &http.Request{} without setting URL).
Common situations: Middleware or tests building requests manually and forgetting to set the URL field; an earlier http.NewRequest failure silently swallowed upstream of the adapter; passing nil into the adapter from a custom route handler.
Related errors
- compat route does not match prefix
- compat upstream base_url
- kms: create request
- request URL is missing
- awscreds: build sts request
AI-assisted analysis of JuliusBrussee/caveman@3ee70a1026 (2026-09-20).
Data as JSON: /api/errors/1badde3b52b03d68.
Report an issue: GitHub.
Appendix: source
Thrown at proxy/providers/openaicompat/openaicompat.go:444
return fmt.Errorf("compat upstream name %q is reserved", name)
default:
return nil
}
}
func ValidateBaseURL(raw string) error {
_, err := parseBaseURL(raw, "compat")
return err
}
// ResolveUpstreamURL intentionally ignores RouteContext.BaseURL. Named mounts
// are configured as independent static upstreams (`compat:` in standalone or
// CAVE_COMPAT_UPSTREAMS in managed mode); applying the generic project
// openai_compatible override here would collapse every named route onto one
// target. The default /compat/ adapter is the route that honors BaseURL.
func (a namedAdapter) ResolveUpstreamURL(_ context.Context, req *http.Request, _ providers.RouteContext) (*url.URL, error) {
if req == nil || req.URL == nil {
return nil, fmt.Errorf("compat request URL is missing")
}
if err := validateCompatPath(req.URL.Path, req.URL.RawPath); err != nil {
return nil, err
}
base, err := parseBaseURL(a.BaseURL, a.Provider)
if err != nil {
return nil, err
}
if !strings.HasPrefix(req.URL.Path, a.prefix+"/") {
return nil, fmt.Errorf("compat route %q does not match prefix %q", req.URL.Path, a.prefix+"/")
}
path := strings.TrimPrefix(req.URL.Path, a.prefix)
base.Path = joinCompatPath(base.Path, path)
base.RawPath = ""
base.RawQuery = joinCompatQuery(base.RawQuery, req.URL.RawQuery)
return base, nil
}
View on GitHub (pinned to 3ee70a1026)