fatedier/frp · error
first and second range numbers are not in pairs
Error message
first and second range numbers are not in pairs
What it means
Thrown by parseNumberRangePair in pkg/config/template.go when building a proxy's port-pair mapping (e.g. TCP port multiplexing / per-port plugin configs that pair two port ranges). Both range strings are expanded into concrete number lists via util.ParseRangeNumbers, and the two lists must contain exactly the same count so element i of the first range maps to element i of the second. If the counts differ, no 1:1 pairing exists and the function aborts with this error. It surfaces during TOML/INI/JSON config conversion into the v1 format, before the client connects.
Source
Thrown at pkg/config/template.go:38
"github.com/fatedier/frp/pkg/util/util"
)
type NumberPair struct {
First int64
Second int64
}
func parseNumberRangePair(firstRangeStr, secondRangeStr string) ([]NumberPair, error) {
firstRangeNumbers, err := util.ParseRangeNumbers(firstRangeStr)
if err != nil {
return nil, err
}
secondRangeNumbers, err := util.ParseRangeNumbers(secondRangeStr)
if err != nil {
return nil, err
}
if len(firstRangeNumbers) != len(secondRangeNumbers) {
return nil, fmt.Errorf("first and second range numbers are not in pairs")
}
pairs := make([]NumberPair, 0, len(firstRangeNumbers))
for i := range firstRangeNumbers {
pairs = append(pairs, NumberPair{
First: firstRangeNumbers[i],
Second: secondRangeNumbers[i],
})
}
return pairs, nil
}
func parseNumberRange(firstRangeStr string) ([]int64, error) {
return util.ParseRangeNumbers(firstRangeStr)
}
View on GitHub (pinned to 6c8a8d0a97)
Solutions
- Make both ranges expand to the same number of ports, e.g. "2000-2003" with "6000-6003" (4 ports each), or pair single values "2000" with "6000".
- Count both sides explicitly: N numbers on the first side requires exactly N numbers on the second side (a range a-b expands to b-a+1 numbers).
- If you intended one value to map to many, restructure the config as multiple proxy entries or use a range on both sides of equal length.
Example fix
# before range1 = "2000-2003" range2 = "6000-6001" # after range1 = "2000-2003" range2 = "6000-6003"
Defensive patterns
Strategy: validation
Validate before calling
// Expand both ranges and require equal lengths before calling parseNumberRangePair.
func rangesPairable(a, b string) error {
na, err := util.ParseRangeNumbers(a)
if err != nil {
return fmt.Errorf("first range invalid: %w", err)
}
nb, err := util.ParseRangeNumbers(b)
if err != nil {
return fmt.Errorf("second range invalid: %w", err)
}
if len(na) != len(nb) {
return fmt.Errorf("range %q has %d numbers but %q has %d; counts must match", a, len(na), b, len(nb))
}
return nil
} Type guard
func isPairableRange(a, b string) bool {
na, err1 := util.ParseRangeNumbers(a)
nb, err2 := util.ParseRangeNumbers(b)
return err1 == nil && err2 == nil && len(na) == len(nb)
} Prevention
- Remember a range a-b expands to b-a+1 numbers; count both sides before pairing.
- Never pair a single value with a multi-value range.
- Add a config lint step that checks paired ranges expand to equal lengths.
When it happens
Trigger: A proxy config declares two ranges that expand to different lengths, e.g. first range "2000-2003" (4 numbers) paired with second range "6000-6001" (2 numbers), or a single value "8080" paired with a range "9000-9002". Any parseNumberRangePair call where len(ParseRangeNumbers(a)) != len(ParseRangeNumbers(b)).
Common situations: Converting an old frp INI/TOML config (with paired port-range settings such as plugin port mappings) where one side of the pair was edited and the other was not; copy-paste of range examples from docs where the sample ranges have different spans; assuming a single value can pair with a multi-value range.
Related errors
- range number is invalid
- exec configuration is required when type is 'exec'
- file path cannot be empty
- exec command cannot be empty
- exec env name cannot be empty
AI-assisted analysis of fatedier/frp@6c8a8d0a97 (2026-08-15).
Data as JSON: /api/errors/70447390f81c9ff0.
Report an issue: GitHub.