JuliusBrussee/caveman · error
compat route path rejected: %w
Error message
compat route path rejected: %w
What it means
Thrown by validateCompatPath (wrapped from validatePathComponents) when a /compat/ path contains an ambiguous or rejected encoding — the underlying causes include a backslash anywhere in the path, repeated path separators (empty middle segments), or encoded-segment mismatches between Path and RawPath. The gate exists because path-encoding ambiguity can bypass prefix stripping and route to unintended upstream paths.
Source
Thrown at proxy/providers/openaicompat/openaicompat.go:264
// Gateways call this with the original URL (including RawPath), while the
// adapter MatchRoute/ResolveUpstreamURL checks provide a second fail-closed
// boundary for direct callers.
func ValidateRequestPath(u *url.URL) error {
if u == nil {
return fmt.Errorf("request URL is missing")
}
if !strings.HasPrefix(u.Path, "/compat/") {
return nil
}
return validateCompatPath(u.Path, u.RawPath)
}
func validateCompatPath(path, rawPath string) error {
if !strings.HasPrefix(path, "/compat/") {
return nil
}
if err := validatePathComponents(path, rawPath); err != nil {
return fmt.Errorf("compat route path rejected: %w", err)
}
return nil
}
func validatePathComponents(path, rawPath string) error {
if strings.Contains(path, `\`) {
return fmt.Errorf("backslash is not allowed in path")
}
segments := strings.Split(path, "/")
for i, segment := range segments {
if segment == "" && i > 0 && i < len(segments)-1 {
return fmt.Errorf("repeated path separators are not allowed")
}
if segment == "." || segment == ".." {
return fmt.Errorf("dot segments are not allowed in path")
}
}
// URL.Path is decoded by net/url while RawPath retains a valid escapedView on GitHub (pinned to 27d5a3981a)
Solutions
- Clean the client URL: single forward slashes only, no backslashes, and let net/http handle encoding (use url.Parse on the full string rather than string concatenation).
- If an upstream genuinely needs an encoded segment, ensure Path and RawPath are consistent (parse the URL, do not hand-set both).
- For fronting proxies, disable path-merging rewrites that can introduce '//' on the /compat/ mount.
Example fix
// before (hand-built, ambiguous)
req, _ := http.NewRequest("POST", baseURL+"/compat//v1/chat/completions", body)
// after
u, _ := url.Parse(baseURL)
u = u.JoinPath("compat", "v1", "chat/completions")
req, _ := http.NewRequest("POST", u.String(), body) Defensive patterns
Strategy: validation
Validate before calling
// reject ambiguous encodings before building the request
if strings.Contains(rawPath, `\`) || strings.Contains(path, `\`) ||
strings.Contains(path[1:], `//`) {
return errors.New("ambiguous compat path encoding")
}
// prefer: let the gateway run openaicompat.ValidateRequestPath(u) on the parsed URL. Try / catch
Map to HTTP 400 at the gateway boundary. These paths are rejected for security reasons — never normalize-and-retry automatically; fix the producing client.
Prevention
- Build client URLs with net/url (Parse/JoinPath) instead of string concatenation.
- Keep fronting proxies from merging path segments on the /compat/ mount.
- Monitor 400s with this message: a spike usually means a client regression or probing.
When it happens
Trigger: Requests to /compat/... whose path contains a literal '\\', an empty interior segment like /compat//v1, percent-encodings that disagree with the decoded form (RawPath inconsistency), or other malformed segments flagged by validatePathComponents.
Common situations: Clients double-encoding or manually concatenating URL parts; a proxy in front rewriting paths and leaving doubled slashes; attack probes with backslashes or %5C trying to escape the mount; hand-built request strings in tests with typos.
Related errors
- cave_mastra_terminal_failure
- cave_harness_incomplete_evidence
- cave_vercel_usage_missing
- cave_eve_runtime_identity_missing
- cave_claude_header_invalid
AI-assisted analysis of JuliusBrussee/caveman@27d5a3981a (2026-08-15).
Data as JSON: /api/errors/eb6e52636bab8dad.
Report an issue: GitHub.