{"record":{"id":"4af5dbd4346374e0","repo":"kubernetes/kops","slug":"found-multiple-securitygroups-with-id-q","errorCode":null,"errorMessage":"found multiple SecurityGroups with ID %q","messagePattern":"found multiple SecurityGroups with ID %q","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"pkg/resources/aws/securitygroup.go","lineNumber":57,"sourceCode":"\t// TODO: Move to a \"pre-execute\" phase?\n\t{\n\t\trequest := &ec2.DescribeSecurityGroupsInput{\n\t\t\tGroupIds: []string{id},\n\t\t}\n\t\tresponse, err := c.EC2().DescribeSecurityGroups(ctx, request)\n\t\tif err != nil {\n\t\t\tif awsup.AWSErrorCode(err) == \"InvalidGroup.NotFound\" {\n\t\t\t\tklog.V(2).Infof(\"Got InvalidGroup.NotFound error describing SecurityGroup %q; will treat as already-deleted\", id)\n\t\t\t\treturn nil\n\t\t\t}\n\t\t\treturn fmt.Errorf(\"error describing SecurityGroup %q: %v\", id, err)\n\t\t}\n\n\t\tif len(response.SecurityGroups) == 0 {\n\t\t\treturn nil\n\t\t}\n\t\tif len(response.SecurityGroups) != 1 {\n\t\t\treturn fmt.Errorf(\"found multiple SecurityGroups with ID %q\", id)\n\t\t}\n\n\t\truleReqest := &ec2.DescribeSecurityGroupRulesInput{\n\t\t\tFilters: []ec2types.Filter{\n\t\t\t\t{Name: aws.String(\"group-id\"), Values: []string{id}},\n\t\t\t},\n\t\t}\n\t\truleResp, err := c.EC2().DescribeSecurityGroupRules(ctx, ruleReqest)\n\t\tif err != nil {\n\t\t\tif awsup.AWSErrorCode(err) == \"InvalidGroup.NotFound\" {\n\t\t\t\tklog.V(2).Infof(\"Got InvalidGroup.NotFound error describing rules for SecurityGroup %q; will treat as already-deleted\", id)\n\t\t\t\treturn nil\n\t\t\t}\n\t\t\treturn fmt.Errorf(\"error describing SecurityGroup rules %q: %v\", id, err)\n\t\t}\n\n\t\tingressRuleIDs := make([]string, 0)\n\t\tfor _, rule := range ruleResp.SecurityGroupRules {","sourceCodeStart":39,"sourceCodeEnd":75,"githubUrl":"https://github.com/kubernetes/kops/blob/4c8573c808a73d578c5eadc86d410646ea0b0d73/pkg/resources/aws/securitygroup.go#L39-L75","documentation":"In DeleteSecurityGroup (pkg/resources/aws/securitygroup.go:57), after DescribeSecurityGroups by ID the code asserts exactly one group is returned. This error means the API returned more than one security group for a single GroupId filter — logically impossible under normal EC2 behavior, so it indicates an unexpected/inconsistent response.","triggerScenarios":"EC2 returning len(response.SecurityGroups) != 1 (and != 0) for a DescribeSecurityGroups call with a single GroupId — e.g. mocked/intercepted API responses, proxies altering results, or future API semantic changes.","commonSituations":"Very rare in practice; seen in tests with faulty mocks, corporate API intermediaries mutating responses, or bespoke EC2-compatible endpoints (e.g. some on-prem/compatible clouds) that do not honor GroupId uniqueness.","solutions":["Confirm you are hitting real AWS EC2, not a compatible/proxied endpoint.","Re-run the delete; transient inconsistency usually does not reproduce.","Check for API-mocking middleware (SDK interceptors, custom endpoint resolvers) distorting the response.","Report upstream (kops issue) if reproducible against real AWS, including SDK version."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// sanity-check the EC2 endpoint before relying on responses\nif strings.Contains(ec2Endpoint, \"mock\") || ec2Endpoint == \"\" && customResolverSet {\n    return fmt.Errorf(\"unexpected EC2 endpoint %q\", ec2Endpoint)\n}","typeGuard":"func expectSingleSG(resp *ec2.DescribeSecurityGroupsOutput) (ec2types.SecurityGroup, bool) {\n    if resp == nil || len(resp.SecurityGroups) != 1 { return ec2types.SecurityGroup{}, false }\n    return resp.SecurityGroups[0], true\n}","tryCatchPattern":"if err := DeleteSecurityGroup(cloud, r); err != nil {\n    if strings.Contains(err.Error(), \"found multiple SecurityGroups\") {\n        klog.Errorf(\"EC2 response invariant broken; check endpoint/proxy: %v\", err)\n    }\n    return err\n}","preventionTips":["Do not point the AWS SDK at unverified EC2-compatible endpoints in production.","Keep SDK interceptors/middleware that could alter responses disabled in deletion paths.","Keep test mocks in sync with real API semantics (one result per GroupId).","Pin known-good aws-sdk-go-v2 versions in deletion tooling."],"tags":["aws","ec2","security-group","invariant-violation"],"backgroundTag":"unexpected-api-response","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"}