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

  1. Format each permission as exactly actions:hosts:ports, e.g. "connect:*.example.com:80,443"
  2. Separate multiple permissions with spaces, not commas: "connect:a.com:80 bind:b.com:8080"
  3. Avoid IPv6 literals in the hosts field (they contain colons); use hostnames or wildcard globs instead
  4. 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

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


AI-assisted analysis of ginuerzh/gost@a33fdbf4c9 (2026-09-02). Data as JSON: /api/errors/d8a75a00f18d9a04. Report an issue: GitHub.