XTLS/Xray-core · error
invalid port: {}
Error message
invalid port: {} What it means
Thrown by PortList.UnmarshalJSON in infra/conf/common.go when the JSON value for a port list is neither a JSON string nor a JSON number. PortList accepts a comma-separated string of ports/ranges or a bare number; objects, arrays, booleans, or null fail both json.Unmarshal attempts and this error wraps the second unmarshal error.
Source
Thrown at infra/conf/common.go:249
return json.Marshal(portStr)
}
}
func (v PortList) String() string {
ports := []string{}
for _, port := range v.Range {
ports = append(ports, port.String())
}
return strings.Join(ports, ",")
}
// UnmarshalJSON implements encoding/json.Unmarshaler.UnmarshalJSON
func (list *PortList) UnmarshalJSON(data []byte) error {
var listStr string
var number uint32
if err := json.Unmarshal(data, &listStr); err != nil {
if err2 := json.Unmarshal(data, &number); err2 != nil {
return errors.New("invalid port: ", string(data)).Base(err2)
}
}
rangelist := strings.Split(listStr, ",")
for _, rangeStr := range rangelist {
trimmed := strings.TrimSpace(rangeStr)
if len(trimmed) > 0 {
if strings.Contains(trimmed, "-") || strings.Contains(trimmed, "env:") {
from, to, err := parseStringPort(trimmed)
if err != nil {
return errors.New("invalid port range: ", trimmed).Base(err)
}
list.Range = append(list.Range, PortRange{From: uint32(from), To: uint32(to)})
} else {
port, err := parseIntPort([]byte(trimmed))
if err != nil {
return errors.New("invalid port: ", trimmed).Base(err)
}
list.Range = append(list.Range, PortRange{From: uint32(port), To: uint32(port)})View on GitHub (pinned to 7d214f8b09)
Solutions
- Use a string: "port": "80,443,1000-2000"
- Or a single number: "port": 443
- Do not use a JSON array for port lists
Example fix
// before "port": [80, 443] // after "port": "80,443"
Defensive patterns
Strategy: validation
Validate before calling
func isPortListJSON(raw []byte) error {
var s string
if json.Unmarshal(raw, &s) == nil {
return nil
}
var n uint32
if json.Unmarshal(raw, &n) == nil {
return nil
}
return errors.New("port list must be a string like \"80,443,1000-2000\" or a number")
} Try / catch
if err := json.Unmarshal(data, &pl); err != nil {
if strings.Contains(err.Error(), "invalid port") {
return fmt.Errorf("routing port field %s: arrays are not supported; use a comma-separated string", data)
}
return err
} Prevention
- Never emit JSON arrays for routing 'port' fields
- Prefer one combined string "80,443,1000-2000" over multiple rules
When it happens
Trigger: Fields typed conf.PortList (e.g. routing rule 'port') given "port": [80, 443] (array form is NOT supported), "port": {"from":1}, or "port": true.
Common situations: Assuming the array form works because StringList accepts arrays — PortList does not; migrating configs from tools that emit arrays of ports.
Related errors
- invalid port range:
- invalid port range {} -> {}
- invalid port range: {}
- invalid portMap: {}
- invalid redirect port: {}
AI-assisted analysis of XTLS/Xray-core@7d214f8b09 (2026-08-15).
Data as JSON: /api/errors/1653e2424857c658.
Report an issue: GitHub.