XTLS/Xray-core · error

invalid port range: {}

Error message

invalid port range: {}

What it means

Thrown by PortRange.UnmarshalJSON in infra/conf/common.go as the final fallback when the JSON value for a port field is neither a valid integer (parseIntPort failed) nor a parseable string port/range (parseJSONStringPort failed). The raw JSON data is appended to the message so you can see the offending value.

Source

Thrown at infra/conf/common.go:209

func (v *PortRange) UnmarshalJSON(data []byte) error {
	port, err := parseIntPort(data)
	if err == nil {
		v.From = uint32(port)
		v.To = uint32(port)
		return nil
	}

	from, to, err := parseJSONStringPort(data)
	if err == nil {
		v.From = uint32(from)
		v.To = uint32(to)
		if v.From > v.To || v.To > math.MaxUint16 {
			return errors.New("invalid port range ", v.From, " -> ", v.To)
		}
		return nil
	}

	return errors.New("invalid port range: ", string(data))
}

type PortList struct {
	Range []PortRange
}

func (list *PortList) Build() *net.PortList {
	portList := new(net.PortList)
	for _, r := range list.Range {
		portList.Range = append(portList.Range, r.Build())
	}
	return portList
}

// MarshalJSON implements encoding/json.Marshaler.MarshalJSON
func (v *PortList) MarshalJSON() ([]byte, error) {
	portStr := v.String()
	port, err := strconv.Atoi(portStr)

View on GitHub (pinned to 7d214f8b09)

Solutions

  1. Set port to an integer 1-65535: "port": 443
  2. Or a valid range string: "port": "1000-2000"
  3. For env: ports ensure the variable is set and numeric before starting Xray
  4. Read the appended raw data in the message to find which value failed

Example fix

// before
"port": "env:HTTPS_PORT"   // variable unset

// after
export HTTPS_PORT=443
"port": "env:HTTPS_PORT"
Defensive patterns

Strategy: validation

Validate before calling

func validatePortJSON(raw []byte) error {
    var n int
    if json.Unmarshal(raw, &n) == nil {
        if n < 1 || n > 65535 {
            return fmt.Errorf("port %d out of range 1-65535", n)
        }
        return nil
    }
    var s string
    if json.Unmarshal(raw, &s) == nil {
        for _, p := range strings.Split(s, ",") {
            if !regexp.MustCompile(`^\d{1,5}(-\d{1,5})?$`).MatchString(strings.TrimSpace(p)) {
                return fmt.Errorf("bad port entry %q", p)
            }
        }
        return nil
    }
    return errors.New("port must be an integer 1-65535 or a range string")
}

Try / catch

if err := json.Unmarshal(data, &portRange); err != nil {
    if strings.Contains(err.Error(), "invalid port range") {
        return fmt.Errorf("port field %s: use 443 or \"1000-2000\" or \"80,443\"", data)
    }
    return err
}

Prevention

When it happens

Trigger: "port": "abc", "port": -1, "port": 0 (PortFromInt rejects 0), "port": true, "port": [443], or "port": null. Also strings containing '-' whose halves are not numbers, like "443-".

Common situations: Unquoted numeric strings that contain spaces; using a protocol name instead of a port; referencing an env variable ("port": "env:PORT") that is unset — it resolves to empty string and parsing fails.

Related errors


AI-assisted analysis of XTLS/Xray-core@7d214f8b09 (2026-08-15). Data as JSON: /api/errors/5117687089c62dc7. Report an issue: GitHub.