ginuerzh/gost · error
permission must have format [actions]:[hosts]:[ports] given:
Error message
permission must have format [actions]:[hosts]:[ports] given: %s
What it means
ParsePermissions splits each permission on ':' and requires exactly 3 parts ([actions]:[hosts]:[ports]). Any token that does not produce exactly three fields hits the default branch at permissions.go:172 and returns this error, aborting the whole parse. IPv6 literals with colons in the hosts field will also exceed 3 parts and trip this error.
Source
Thrown at permissions.go:172
}
hosts, err := ParseStringSet(parts[1])
if err != nil {
return nil, fmt.Errorf("hosts list must look like google.pl,*.google.com given: %s", parts[1])
}
ports, err := ParsePortSet(parts[2])
if err != nil {
return nil, fmt.Errorf("ports list must look like 80,8000-9000, given: %s", parts[2])
}
permission := Permission{Actions: *actions, Hosts: *hosts, Ports: *ports}
*ps = append(*ps, permission)
default:
return nil, fmt.Errorf("permission must have format [actions]:[hosts]:[ports] given: %s", perm)
}
}
return ps, nil
}
// Can tests whether the given action and host:port is allowed by this Permissions.
func (ps *Permissions) Can(action string, host string, port int) bool {
for _, p := range *ps {
if p.Actions.Contains(action) && p.Hosts.Contains(host) && p.Ports.Contains(port) {
return true
}
}
return false
}
func minint(x, y int) int {View on GitHub (pinned to a33fdbf4c9)
Solutions
- Format each permission as exactly actions:hosts:ports, e.g. "connect:*.example.com:80,443"
- Separate multiple permissions with spaces, not commas: "connect:a.com:80 bind:b.com:8080"
- Avoid IPv6 literals in the hosts field (they contain colons); use hostnames or wildcard globs instead
- Pre-check with strings.Count(perm, ":") == 2 before calling ParsePermissions
Example fix
// before
perms, err := gost.ParsePermissions("connect:8080")
// after
perms, err := gost.ParsePermissions("connect:*.example.com:8080") Defensive patterns
Strategy: validation
Validate before calling
func validPermissionFormat(perm string) bool {
return strings.Count(perm, ":") == 2 && perm != ""
}
for _, perm := range strings.Fields(input) {
if !validPermissionFormat(perm) { return fmt.Errorf("bad permission: %q", perm) }
} Type guard
func isThreePartPermission(perm string) bool { return len(strings.Split(perm, ":")) == 3 } Try / catch
perms, err := gost.ParsePermissions(input)
if err != nil {
if strings.Contains(err.Error(), "must have format [actions]:[hosts]:[ports]") {
log.Fatalf("permission %q must be actions:hosts:ports: %v", input, err)
}
return err
} Prevention
- Keep the strict 3-segment actions:hosts:ports layout per permission entry
- Separate multiple permissions with spaces, not commas
- Do not put IPv6 addresses (extra colons) in the hosts field; use hostnames or globs
When it happens
Trigger: Calling ParsePermissions with a permission missing colons ("connectgoogle.pl80"), with too few fields ("connect:80"), or with extra colons such as IPv6 hosts ("connect:::1:80") — anything where strings.Split(perm, ":") yields len(parts) != 3.
Common situations: Users writing gost permission strings from memory and forgetting the 3-part layout, pasting IPv6 addresses into the hosts field, or separating multiple permissions with commas instead of spaces.
Related errors
- hosts list must look like google.pl,*.google.com given: %s
- ErrInvalidNode
- ports list must look like 80,8000-9000, given: %s
- must specify at least one port
- cannot be empty
AI-assisted analysis of ginuerzh/gost@a33fdbf4c9 (2026-09-02).
Data as JSON: /api/errors/d8a75a00f18d9a04.
Report an issue: GitHub.