JuliusBrussee/caveman · error
compat request URL is missing
Error message
compat request URL is missing
What it means
Thrown by namedAdapter.ResolveUpstreamURL when req is nil or req.URL is nil. Named compat adapters (independent static upstreams configured via compat: entries or CAVE_COMPAT_UPSTREAMS) need the request URL to validate the path and compute the upstream path, so a request with no URL fails closed instead of panicking.
Source
Thrown at proxy/providers/openaicompat/openaicompat.go:226
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 27d5a3981a)
Solutions
- Ensure the request passed to the adapter is a fully formed *http.Request with a non-nil URL (use http.NewRequest or httptest.NewRequest).
- If writing direct-call code, guard with `if req == nil || req.URL == nil { ... }` before calling ResolveUpstreamURL.
- Prefer calling the adapter through the gateway's normal request lifecycle, which always supplies a parsed URL.
Example fix
// before
req := &http.Request{Header: hdr}
u, err := adapter.ResolveUpstreamURL(ctx, req, route)
// after
req := httptest.NewRequest("POST", "/compat/myupstream/v1/chat/completions", body)
u, err := adapter.ResolveUpstreamURL(ctx, req, route) Defensive patterns
Strategy: validation
Validate before calling
if req == nil || req.URL == nil {
return errors.New("cannot resolve upstream: request URL missing")
}
u, err := adapter.ResolveUpstreamURL(ctx, req, route) Try / catch
Treat as an internal invariant violation: return 500 and log a stack trace; no retry. A nil URL here means a bug in the caller's middleware, not a transient fault.
Prevention
- Always build requests with http.NewRequest / httptest.NewRequest so URL is never nil.
- In middleware chains, propagate the original request rather than reconstructing partial clones.
- Add a nil-request test case to any code that calls adapter ResolveUpstreamURL directly.
When it happens
Trigger: Invoking namedAdapter.ResolveUpstreamURL(nil, ...) or with a *http.Request whose URL field is nil — typically a hand-constructed request in tests or a middleware bug that drops the URL before the adapter runs.
Common situations: Unit tests constructing &http.Request{} without setting URL; a middleware chain that replaces the request with an incomplete clone; calling the adapter directly instead of through the gateway that always provides a parsed URL.
Related errors
- request URL is missing
- cave_execution_authorization_private
- caveman agent: file path is required
- caveman agent: invalid tool name ${JSON.stringify(options.na
- caveman agent: unknown tool effect ${JSON.stringify(options.
AI-assisted analysis of JuliusBrussee/caveman@27d5a3981a (2026-08-15).
Data as JSON: /api/errors/1badde3b52b03d68.
Report an issue: GitHub.