{"record":{"id":"d8a75a00f18d9a04","repo":"ginuerzh/gost","slug":"permission-must-have-format-actions-hosts-por","errorCode":null,"errorMessage":"permission must have format [actions]:[hosts]:[ports] given: %s","messagePattern":"permission must have format \\[actions\\]:\\[hosts\\]:\\[ports\\] given: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"permissions.go","lineNumber":172,"sourceCode":"\t\t\t}\n\n\t\t\thosts, err := ParseStringSet(parts[1])\n\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"hosts list must look like google.pl,*.google.com given: %s\", parts[1])\n\t\t\t}\n\n\t\t\tports, err := ParsePortSet(parts[2])\n\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"ports list must look like 80,8000-9000, given: %s\", parts[2])\n\t\t\t}\n\n\t\t\tpermission := Permission{Actions: *actions, Hosts: *hosts, Ports: *ports}\n\n\t\t\t*ps = append(*ps, permission)\n\t\tdefault:\n\t\t\treturn nil, fmt.Errorf(\"permission must have format [actions]:[hosts]:[ports] given: %s\", perm)\n\t\t}\n\t}\n\n\treturn ps, nil\n}\n\n// Can tests whether the given action and host:port is allowed by this Permissions.\nfunc (ps *Permissions) Can(action string, host string, port int) bool {\n\tfor _, p := range *ps {\n\t\tif p.Actions.Contains(action) && p.Hosts.Contains(host) && p.Ports.Contains(port) {\n\t\t\treturn true\n\t\t}\n\t}\n\n\treturn false\n}\n\nfunc minint(x, y int) int {","sourceCodeStart":154,"sourceCodeEnd":190,"githubUrl":"https://github.com/ginuerzh/gost/blob/a33fdbf4c98034f4bfeeaea9868909822b9c526d/permissions.go#L154-L190","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\nperms, err := gost.ParsePermissions(\"connect:8080\")\n// after\nperms, err := gost.ParsePermissions(\"connect:*.example.com:8080\")","handlingStrategy":"validation","validationCode":"func validPermissionFormat(perm string) bool {\n    return strings.Count(perm, \":\") == 2 && perm != \"\"\n}\nfor _, perm := range strings.Fields(input) {\n    if !validPermissionFormat(perm) { return fmt.Errorf(\"bad permission: %q\", perm) }\n}","typeGuard":"func isThreePartPermission(perm string) bool { return len(strings.Split(perm, \":\")) == 3 }","tryCatchPattern":"perms, err := gost.ParsePermissions(input)\nif err != nil {\n    if strings.Contains(err.Error(), \"must have format [actions]:[hosts]:[ports]\") {\n        log.Fatalf(\"permission %q must be actions:hosts:ports: %v\", input, err)\n    }\n    return err\n}","preventionTips":["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"],"tags":["config","parsing","validation","gost"],"backgroundTag":"config-parse-error","analyzedSha":"a33fdbf4c98034f4bfeeaea9868909822b9c526d","analyzedAt":"2026-09-02T22:15:54.506Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-10T02:17:09.455Z"}