{"record":{"id":"62ba40881ee624a3","repo":"kubernetes/kops","slug":"unable-to-tag-subnet-v-62ba40","errorCode":null,"errorMessage":"unable to tag subnet %v","messagePattern":"unable to tag subnet (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"upup/pkg/fi/cloudup/awstasks/natgateway.go","lineNumber":346,"sourceCode":"\n\terr := t.AddAWSTags(*e.ID, e.Tags)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"unable to tag NatGateway\")\n\t}\n\n\t// Tag the associated subnet\n\tif e.Subnet == nil {\n\t\treturn fmt.Errorf(\"Subnet not set\")\n\t} else if e.Subnet.ID == nil {\n\t\treturn fmt.Errorf(\"Subnet ID not set\")\n\t}\n\n\t// TODO: AssociatedNatgateway tag is obsolete - we can get from the route table instead\n\ttags := make(map[string]string)\n\ttags[\"AssociatedNatgateway\"] = *id\n\terr = t.AddAWSTags(*e.Subnet.ID, tags)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"unable to tag subnet %v\", err)\n\t}\n\n\t// If this is a shared NGW, we need to tag it\n\t// The tag that implies \"shared\" is `AssociatedNatgateway`=> NGW-ID\n\t// This is better than just a tag that's shared because this lets us create a whitelist of these NGWs\n\t// without doing a bunch more work in `kutil/delete_cluster.go`\n\n\tif fi.ValueOf(e.Shared) {\n\t\tif e.AssociatedRouteTable == nil {\n\t\t\treturn fmt.Errorf(\"AssociatedRouteTable not provided\")\n\t\t}\n\t\tklog.V(2).Infof(\"tagging route table %s to track shared NGW\", fi.ValueOf(e.AssociatedRouteTable.ID))\n\t\terr = t.AddAWSTags(fi.ValueOf(e.AssociatedRouteTable.ID), tags)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"unable to tag route table %v\", err)\n\t\t}\n\t}\n","sourceCodeStart":328,"sourceCodeEnd":364,"githubUrl":"https://github.com/kubernetes/kops/blob/4c8573c808a73d578c5eadc86d410646ea0b0d73/upup/pkg/fi/cloudup/awstasks/natgateway.go#L328-L364","documentation":"Right after validating the subnet, RenderAWS tags the subnet with AssociatedNatgateway=<ngw-id> via t.AddAWSTags. If that AWS ec2 CreateTags call fails, the error is wrapped as \"unable to tag subnet %v\".","triggerScenarios":"AddAWSTags(*e.Subnet.ID, tags) returns an error during RenderAWS — e.g. AWS API error (throttling, InvalidSubnetID.NotFound, permission denied on ec2:CreateTags for the subnet).","commonSituations":"IAM policy lacking ec2:CreateTags on shared subnet ARNs; subnet deleted out-of-band between discovery and tagging; transient AWS throttling during apply.","solutions":["Read the wrapped %v cause: if it is UnauthorizedOperation, grant ec2:CreateTags on the subnet in the kops IAM policy","If InvalidSubnetID.NotFound, re-run kops update — the subnet no longer exists and must be recreated","Retry the apply on transient AWS errors (throttling); consider reducing concurrent API calls","Verify the subnet ID from the spec exists in the target region/account"],"exampleFix":"// before (IAM policy for kops controllers missing subnet tag permission)\n{ \"Effect\": \"Deny\", ... subnet resources }\n// after\nallow ec2:CreateTags on arn:aws:ec2:*:*:subnet/* for the kops principal","handlingStrategy":"retry","validationCode":"_, err := cloud.EC2().DescribeSubnets(&ec2.DescribeSubnetsInput{SubnetIds: []string{*subnetID}})\nif err != nil { return fmt.Errorf(\"subnet %s not taggable/visible: %w\", *subnetID, err) }","typeGuard":null,"tryCatchPattern":"err := apply()\nvar awsErr smithy.APIError\nif errors.As(err, &awsErr) && awsErr.ErrorCode() == \"ThrottlingException\" {\n    time.Sleep(backoff); retry()\n}","preventionTips":["Ensure IAM policy includes ec2:CreateTags on subnet ARNs","Retry applies on transient AWS errors","Confirm the subnet still exists before applying"],"tags":["aws","nat-gateway","tagging","permissions"],"backgroundTag":"aws-tag-permission-denied","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"}