fatedier/frp · error

range number is invalid, %v

Error message

range number is invalid, %v

What it means

Thrown while unmarshalling a PortsRange value (pkg/config/types/types.go) when a comma-separated port list contains a single token that is not a valid 64-bit integer. The parser splits the string on commas, then on '-'; a token with no dash is treated as a single port and must parse with strconv.ParseInt. Any syntax or overflow failure (wrapped with %v) produces this error during PortsRange.UnmarshalJSON.

Source

Thrown at pkg/config/types/types.go:151

	return strings.Join(strs, ",")
}

// the format of str is like "1000-2000,3000,4000-5000"
func NewPortsRangeSliceFromString(str string) ([]PortsRange, error) {
	str = strings.TrimSpace(str)
	out := []PortsRange{}
	numRanges := strings.SplitSeq(str, ",")
	for numRangeStr := range numRanges {
		// 1000-2000 or 2001
		numArray := strings.Split(numRangeStr, "-")
		// length: only 1 or 2 is correct
		rangeType := len(numArray)
		switch rangeType {
		case 1:
			// single number
			singleNum, err := strconv.ParseInt(strings.TrimSpace(numArray[0]), 10, 64)
			if err != nil {
				return nil, fmt.Errorf("range number is invalid, %v", err)
			}
			out = append(out, PortsRange{Single: int(singleNum)})
		case 2:
			// range numbers
			minNum, err := strconv.ParseInt(strings.TrimSpace(numArray[0]), 10, 64)
			if err != nil {
				return nil, fmt.Errorf("range number is invalid, %v", err)
			}
			maxNum, err := strconv.ParseInt(strings.TrimSpace(numArray[1]), 10, 64)
			if err != nil {
				return nil, fmt.Errorf("range number is invalid, %v", err)
			}
			if maxNum < minNum {
				return nil, fmt.Errorf("range number is invalid")
			}
			out = append(out, PortsRange{Start: int(minNum), End: int(maxNum)})
		default:
			return nil, fmt.Errorf("range number is invalid")

View on GitHub (pinned to 6c8a8d0a97)

Solutions

  1. Correct the offending token to a plain decimal integer within int64 range (and practical port range 0-65535), e.g. "8080".
  2. Remove trailing/leading commas and stray whitespace in the comma-separated port list.
  3. Replace service names with their numeric port equivalents (http -> 80, ssh -> 22).

Example fix

# before
remotePort = "80 80"

# after
remotePort = 8080
Defensive patterns

Strategy: validation

Validate before calling

// Validate every comma-separated token is a plain int64 before unmarshalling.
func validPortsString(s string) error {
	for _, tok := range strings.Split(s, ",") {
		if _, err := strconv.ParseInt(strings.TrimSpace(tok), 10, 64); err != nil {
			return fmt.Errorf("bad port token %q: %w", tok, err)
		}
	}
	return nil
}

Type guard

func isPlainPort(s string) bool {
	_, err := strconv.ParseInt(strings.TrimSpace(s), 10, 64)
	return err == nil
}

Prevention

When it happens

Trigger: PortsRange JSON unmarshal on input like "808 0" (space), "0x50" (hex not supported), "http" (non-numeric), "99999999999999999999" (int64 overflow), or a trailing comma producing an empty token.

Common situations: Typos in remotePort/localPort strings in frpc TOML/JSON; pasting IANA service names ("http", "ssh") where frp expects numeric ports; a trailing comma in a JSON port list; values copied from a spreadsheet with non-breaking spaces or thousand separators.

Related errors


AI-assisted analysis of fatedier/frp@6c8a8d0a97 (2026-08-15). Data as JSON: /api/errors/4d3de3210e2d4010. Report an issue: GitHub.