{"record":{"id":"d830fc66dc410a87","repo":"kubernetes/kops","slug":"sourceranges-and-sourcetags-should-not-both-be-spe","errorCode":null,"errorMessage":"SourceRanges and SourceTags should not both be specified","messagePattern":"SourceRanges and SourceTags should not both be specified","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"upup/pkg/fi/cloudup/gcetasks/firewallrule.go","lineNumber":110,"sourceCode":"func (e *FirewallRule) Run(c *fi.CloudupContext) error {\n\treturn fi.CloudupDefaultDeltaRunMethod(e, c)\n}\n\n// Normalize applies some validation that isn't technically required,\n// but avoids some problems with surprising behaviours.\nfunc (e *FirewallRule) Normalize(c *fi.CloudupContext) error {\n\tif !e.Disabled {\n\t\t// Treat it as an error if SourceRanges _and_ SourceTags empty with Disabled=false\n\t\t// this is interpreted as SourceRanges=\"0.0.0.0/0\", which is likely not what was intended.\n\t\tif len(e.SourceRanges) == 0 && len(e.SourceTags) == 0 {\n\t\t\treturn fmt.Errorf(\"either SourceRanges or SourceTags should be specified when Disabled is false\")\n\t\t}\n\t}\n\n\t// Treat it as an error if SourceRanges _and_ SourceTags both set;\n\t// this is interpreted as OR, not AND, which is likely not what was intended.\n\tif len(e.SourceRanges) != 0 && len(e.SourceTags) != 0 {\n\t\treturn fmt.Errorf(\"SourceRanges and SourceTags should not both be specified\")\n\t}\n\n\tname := fi.ValueOf(e.Name)\n\n\t// Make sure we've split the ipv4 / ipv6 addresses.\n\t// A single firewall rule can't mix ipv4 and ipv6 addresses, so we split them into two rules.\n\tfor _, sourceRange := range e.SourceRanges {\n\t\t_, cidr, err := net.ParseCIDR(sourceRange)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"sourceRange %q is not valid: %w\", sourceRange, err)\n\t\t}\n\n\t\tif e.Family == \"\" {\n\t\t\t// This is our own requirement, just for consistency checking.\n\t\t\t// Previous we used the name, but that was confused when the cluster name was ipv6.example.com\n\t\t\treturn fmt.Errorf(\"must set Family when using SourceRanges\")\n\t\t}\n","sourceCodeStart":92,"sourceCodeEnd":128,"githubUrl":"https://github.com/kubernetes/kops/blob/4c8573c808a73d578c5eadc86d410646ea0b0d73/upup/pkg/fi/cloudup/gcetasks/firewallrule.go#L92-L128","documentation":"GCE treats SourceRanges and SourceTags as OR, not AND, which developers usually do not expect. Normalize rejects specs that set both so kOps never creates a rule that is broader than the author intended.","triggerScenarios":"A firewallRule in the cluster spec has non-empty sourceRanges AND non-empty sourceTags simultaneously.","commonSituations":"Merging two rule configs during refactoring; assuming the fields combine as AND; copy-pasting rules that each had only one of the fields.","solutions":["Keep only sourceRanges if CIDR restriction is intended","Keep only sourceTags if tag-based restriction is intended","Split into two separate FirewallRule tasks if you genuinely need both rule types","Re-run kops update after editing the manifest"],"exampleFix":"// before\nsourceRanges: [\"10.0.0.0/8\"]\nsourceTags: [\"my-tag\"]\n// after\nsourceRanges: [\"10.0.0.0/8\"]","handlingStrategy":"validation","validationCode":"func validateExclusiveSources(rule FirewallRuleSpec) error {\n  if len(rule.SourceRanges) != 0 && len(rule.SourceTags) != 0 {\n    return fmt.Errorf(\"rule %s: use sourceRanges OR sourceTags, not both (GCE ORs them)\", rule.Name)\n  }\n  return nil\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Remember GCE semantics: ranges and tags are ORed","Split into two rules when both dimensions are needed","Code-review firewall manifest changes for combined sources"],"tags":["gcp","gce","firewall","validation"],"backgroundTag":"conflicting-firewall-source","analyzedSha":"4c8573c808a73d578c5eadc86d410646ea0b0d73","analyzedAt":"2026-09-05T04:13:19.212Z","contentChangedAt":"2026-09-05T04:13:19.212Z","schemaVersion":2},"datasetVersion":"2026-09-12T12:17:11.808Z"}