XTLS/Xray-core · error
Trojan fallbacks: "path" must be empty or start with "/"
Error message
Trojan fallbacks: "path" must be empty or start with "/"
What it means
Thrown while validating Trojan inbound fallbacks: any non-empty 'path' must start with '/' because it is matched as an HTTP path prefix. A path like "ws" or "api/v1" is rejected.
Source
Thrown at infra/conf/trojan.go:175
_ = json.Unmarshal(fb.Dest, &s)
}
config.Fallbacks = append(config.Fallbacks, &trojan.Fallback{
Name: fb.Name,
Alpn: fb.Alpn,
Path: fb.Path,
Type: fb.Type,
Dest: s,
Xver: fb.Xver,
})
}
for _, fb := range config.Fallbacks {
/*
if fb.Alpn == "h2" && fb.Path != "" {
return nil, errors.New(`Trojan fallbacks: "alpn":"h2" doesn't support "path"`)
}
*/
if fb.Path != "" && fb.Path[0] != '/' {
return nil, errors.New(`Trojan fallbacks: "path" must be empty or start with "/"`)
}
if fb.Type == "" && fb.Dest != "" {
if fb.Dest == "serve-ws-none" {
fb.Type = "serve"
} else if filepath.IsAbs(fb.Dest) || fb.Dest[0] == '@' {
fb.Type = "unix"
if strings.HasPrefix(fb.Dest, "@@") && (runtime.GOOS == "linux" || runtime.GOOS == "android") {
fullAddr := make([]byte, len(syscall.RawSockaddrUnix{}.Path)) // may need padding to work with haproxy
copy(fullAddr, fb.Dest[1:])
fb.Dest = string(fullAddr)
}
} else {
if _, err := strconv.Atoi(fb.Dest); err == nil {
fb.Dest = "localhost:" + fb.Dest
}
if _, _, err := net.SplitHostPort(fb.Dest); err == nil {
fb.Type = "tcp"
}View on GitHub (pinned to 7d214f8b09)
Solutions
- Prefix the path with '/': "path": "/ws"
- Omit "path" entirely if the fallback should catch all unmatched requests
Example fix
// before
{ "dest": 80, "path": "ws" }
// after
{ "dest": 80, "path": "/ws" } Defensive patterns
Strategy: validation
Validate before calling
for _, fb := range fallbacks {
p := gjson.Get(fb.Raw, "path").String()
if p != "" && !strings.HasPrefix(p, "/") {
return fmt.Errorf("fallback path %q must start with '/'", p)
}
} Prevention
- Normalize all HTTP paths with a leading slash in templates
- Mirror the exact path between server fallbacks and client wsPath
When it happens
Trigger: A fallback object { "dest": 80, "path": "ws" } — missing the leading slash — in a Trojan inbound's "fallbacks" array.
Common situations: Adapting an nginx/caddy location string that omitted the slash, or copying a WebSocket path from a client share link (which often shows it without '/').
Related errors
- Trojan fallbacks: please fill in a valid value for every "de
- Trojan fallbacks: invalid PROXY protocol version, "xver" onl
- failed to find the default "name" config
- failed to find the default "alpn" config
- failed to find the default "path" config
AI-assisted analysis of XTLS/Xray-core@7d214f8b09 (2026-08-15).
Data as JSON: /api/errors/850d726758474a18.
Report an issue: GitHub.