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 escaped

View on GitHub (pinned to 27d5a3981a)

Solutions

  1. 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).
  2. If an upstream genuinely needs an encoded segment, ensure Path and RawPath are consistent (parse the URL, do not hand-set both).
  3. 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

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


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