JuliusBrussee/caveman · error
backslash is not allowed in path
Error message
backslash is not allowed in path
What it means
validatePathComponents rejects any path containing a backslash byte. Backslashes are path separators on Windows and are normalized differently by various decoders, so allowing them could change route identity across proxy hops. Applies to /compat/ paths and to configured upstream base URLs.
Solutions
- Replace the backslash with a forward slash in the path
- Fix the upstream BaseURL config value to use forward slashes
- If the backslash is meaningful data, move it to the query string or request body, properly percent-encoded
Example fix
// before BaseURL: "https://upstream.example.com\v1" // after BaseURL: "https://upstream.example.com/v1"
Defensive patterns
Strategy: validation
Validate before calling
if strings.Contains(rawURL, "\\") {
return errors.New("backslash not allowed in URL")
} Try / catch
if err := ValidateBaseURL(cfg.BaseURL); err != nil {
return fmt.Errorf("invalid upstream config: %w", err)
} Prevention
- Always use forward slashes in URLs regardless of OS
- Lint config files for backslashes in URL fields
When it happens
Trigger: Request path like /compat/openai\v1/chat; an upstream BaseURL configured with a backslash; a client copying a Windows-style path into an API URL.
Common situations: Windows developers pasting file-system-like paths into API clients; config values copied from Windows machines; malicious clients probing separator-confusion.
Understand the failure class
Background: Path traversal blocked: "path escapes the workspace" and "outside site root" errors when a path will not stay inside its allowed directory — this error's family across 26 libraries.
Related errors
- ambiguous escaped path sequence
- compat route path rejected
- dot segments are not allowed in path
- repeated path separators are not allowed
- caveman-code: path escapes the workspace
AI-assisted analysis of JuliusBrussee/caveman@3ee70a1026 (2026-09-20).
Data as JSON: /api/errors/ed4d30896257f477.
Report an issue: GitHub.
Appendix: source
Thrown at proxy/providers/openaicompat/openaicompat.go:489
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
// spelling. Reject separators, backslashes, and dot bytes in either form so
// a path cannot change route identity after another decoder or proxy hop.
for _, escape := range []string{"%2f", "%5c", "%2e"} {
if strings.Contains(strings.ToLower(path), escape) || strings.Contains(strings.ToLower(rawPath), escape) {
return fmt.Errorf("ambiguous escaped path sequence %s", escape)
}
}View on GitHub (pinned to 3ee70a1026)