{"record":{"id":"6fea5d24312818d1","repo":"kubernetes/kops","slug":"cannot-parse-rule-q-v-6fea5d","errorCode":null,"errorMessage":"cannot parse rule %q: %v","messagePattern":"cannot parse rule %q: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"upup/pkg/fi/cloudup/openstacktasks/securitygroup.go","lineNumber":158,"sourceCode":"\n\tcloud := c.T.Cloud.(openstack.OpenstackCloud)\n\tif s.RemoveGroup {\n\t\tsg, err := getSecurityGroupByName(s, cloud)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tif sg != nil {\n\t\t\tremovals = append(removals, &deleteSecurityGroup{\n\t\t\t\tsecurityGroup: sg,\n\t\t\t})\n\t\t}\n\t}\n\n\tvar rules []RemovalRule\n\tfor _, r := range s.RemoveExtraRules {\n\t\trule, err := ParseRemovalRule(r)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"cannot parse rule %q: %v\", r, err)\n\t\t}\n\t\trules = append(rules, rule)\n\t}\n\n\tsg, err := getSecurityGroupByName(s, cloud)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif sg == nil {\n\t\treturn nil, nil\n\t}\n\n\tsgRules, err := cloud.ListSecurityGroupRules(sgr.ListOpts{\n\t\tSecGroupID: fi.ValueOf(sg.ID),\n\t})\n\tif err != nil {\n\t\treturn nil, err\n\t}","sourceCodeStart":140,"sourceCodeEnd":176,"githubUrl":"https://github.com/kubernetes/kops/blob/4c8573c808a73d578c5eadc86d410646ea0b0d73/upup/pkg/fi/cloudup/openstacktasks/securitygroup.go#L140-L176","documentation":"FindDeletions parses each entry of the SecurityGroup task's RemoveExtraRules list with ParseRemovalRule; this error is returned when a rule string does not conform to the internal rule DSL. The only accepted syntax is `port=N` (with exactly one '=' and an integer N); anything else, including a non-integer port, yields \"cannot parse rule %q: %v\".","triggerScenarios":"A RemoveExtraRules entry like \"port=abc\", \"ports=443\", \"port=\", or \"tcp=443\" is passed; ParseRemovalRule splits on '=' and either finds an unknown key, fails strconv.Atoi, or does not find exactly 2 tokens.","commonSituations":"Cluster spec typos in the securityGroupOverride / removeExtraRules configuration; copying rules from docs of a different kOps version where the DSL changed; YAML quoting issues turning numbers into strings like \"port=443 \" with stray whitespace or units (\"port=443/tcp\").","solutions":["Read the %q in the message to see the offending rule string.","Rewrite the rule as exactly `port=<integer>`, e.g. \"port=443\" — the DSL supports only this form.","Remove trailing whitespace/units and ensure the key is lowercase `port`.","If you intended to remove rules other than by port, remove the entry from RemoveExtraRules instead of guessing syntax (the language is internal and unstable)."],"exampleFix":"// before (cluster spec)\nremoveExtraRules:\n  - port=443/tcp\n// after\nremoveExtraRules:\n  - port=443","handlingStrategy":"validation","validationCode":"func validRemovalRule(r string) bool {\n\tr = strings.TrimSpace(r)\n\ttoks := strings.Split(r, \"=\")\n\tif len(toks) != 2 || toks[0] != \"port\" {\n\t\treturn false\n\t}\n\t_, err := strconv.Atoi(toks[1])\n\treturn err == nil\n}\n// validate each entry of RemoveExtraRules before saving the cluster spec","typeGuard":null,"tryCatchPattern":"rule, err := ParseRemovalRule(r)\nif err != nil {\n\tklog.Errorf(\"skipping invalid RemoveExtraRules entry %q: %v\", r, err)\n\tcontinue // or fail fast with a clear config-validation error\n}","preventionTips":["Only use the documented `port=N` syntax in removeExtraRules.","Quote rule strings in YAML to avoid type coercion.","Add cluster-spec validation/linting for RemoveExtraRules entries.","Remember the DSL is internal/unstable — pin the kOps version your spec targets."],"tags":["openstack","security-group","config-parsing","validation"],"backgroundTag":"invalid-rule-syntax","analyzedSha":"4c8573c808a73d578c5eadc86d410646ea0b0d73","analyzedAt":"2026-09-05T04:13:19.212Z","contentChangedAt":"2026-09-05T04:13:19.212Z","schemaVersion":2},"datasetVersion":"2026-09-12T07:17:12.445Z"}