kubernetes/kops · warning
found multiple SecurityGroups with ID %q
Error message
found multiple SecurityGroups with ID %q
What it means
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.
Source
Thrown at pkg/resources/aws/securitygroup.go:57
// TODO: Move to a "pre-execute" phase?
{
request := &ec2.DescribeSecurityGroupsInput{
GroupIds: []string{id},
}
response, err := c.EC2().DescribeSecurityGroups(ctx, request)
if err != nil {
if awsup.AWSErrorCode(err) == "InvalidGroup.NotFound" {
klog.V(2).Infof("Got InvalidGroup.NotFound error describing SecurityGroup %q; will treat as already-deleted", id)
return nil
}
return fmt.Errorf("error describing SecurityGroup %q: %v", id, err)
}
if len(response.SecurityGroups) == 0 {
return nil
}
if len(response.SecurityGroups) != 1 {
return fmt.Errorf("found multiple SecurityGroups with ID %q", id)
}
ruleReqest := &ec2.DescribeSecurityGroupRulesInput{
Filters: []ec2types.Filter{
{Name: aws.String("group-id"), Values: []string{id}},
},
}
ruleResp, err := c.EC2().DescribeSecurityGroupRules(ctx, ruleReqest)
if err != nil {
if awsup.AWSErrorCode(err) == "InvalidGroup.NotFound" {
klog.V(2).Infof("Got InvalidGroup.NotFound error describing rules for SecurityGroup %q; will treat as already-deleted", id)
return nil
}
return fmt.Errorf("error describing SecurityGroup rules %q: %v", id, err)
}
ingressRuleIDs := make([]string, 0)
for _, rule := range ruleResp.SecurityGroupRules {View on GitHub (pinned to 4c8573c808)
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.
Defensive patterns
Strategy: validation
Validate before calling
// sanity-check the EC2 endpoint before relying on responses
if strings.Contains(ec2Endpoint, "mock") || ec2Endpoint == "" && customResolverSet {
return fmt.Errorf("unexpected EC2 endpoint %q", ec2Endpoint)
} Type guard
func expectSingleSG(resp *ec2.DescribeSecurityGroupsOutput) (ec2types.SecurityGroup, bool) {
if resp == nil || len(resp.SecurityGroups) != 1 { return ec2types.SecurityGroup{}, false }
return resp.SecurityGroups[0], true
} Try / catch
if err := DeleteSecurityGroup(cloud, r); err != nil {
if strings.Contains(err.Error(), "found multiple SecurityGroups") {
klog.Errorf("EC2 response invariant broken; check endpoint/proxy: %v", err)
}
return err
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- found multiple instances with instance id: %s
- found multiple InternetGateways with id %q
- error describing SecurityGroup %q: %v
- error describing SecurityGroup rules %q: %v
- cannot revoke ingress for ID %q with rule IDs %v: %v
AI-assisted analysis of kubernetes/kops@4c8573c808 (2026-09-05).
Data as JSON: /api/errors/4af5dbd4346374e0.
Report an issue: GitHub.