{"record":{"id":"15f4dc81d9a7b11e","repo":"kubernetes/kops","slug":"unable-to-tag-natgateway","errorCode":null,"errorMessage":"unable to tag NatGateway","messagePattern":"unable to tag NatGateway","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"upup/pkg/fi/cloudup/awstasks/natgateway.go","lineNumber":331,"sourceCode":"\n\t\trequest := &ec2.CreateNatGatewayInput{\n\t\t\tTagSpecifications: awsup.EC2TagSpecification(ec2types.ResourceTypeNatgateway, e.Tags),\n\t\t}\n\t\trequest.AllocationId = e.ElasticIP.ID\n\t\trequest.SubnetId = e.Subnet.ID\n\t\tresponse, err := t.Cloud.EC2().CreateNatGateway(ctx, request)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"Error creating Nat Gateway: %v\", err)\n\t\t}\n\t\te.ID = response.NatGateway.NatGatewayId\n\t\tid = e.ID\n\t} else {\n\t\tid = a.ID\n\t}\n\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","sourceCodeStart":313,"sourceCodeEnd":349,"githubUrl":"https://github.com/kubernetes/kops/blob/4c8573c808a73d578c5eadc86d410646ea0b0d73/upup/pkg/fi/cloudup/awstasks/natgateway.go#L313-L349","documentation":"After creating/locating the NAT gateway, RenderAWS applies the task's tags with t.AddAWSTags. That call failed, so the gateway exists but is untagged — kops relies on these tags (e.g. KubernetesCluster, AssociatedNatgateway) for later lookups, so the error is not swallowed.","triggerScenarios":"t.AddAWSTags(*e.ID, e.Tags) returns err — note the original err detail is dropped, so the cause is hidden: typically CreateTags AccessDenied, throttling, or a just-created gateway not yet visible to the Tags API.","commonSituations":"IAM policy missing ec2:CreateTags; API throttling right after creation; eventual-consistency window where the new gateway ID isn't yet taggable.","solutions":["Re-run `kops update cluster --yes` to retry tagging the now-existing gateway","Ensure IAM policy includes ec2:CreateTags on the cluster resources","If it recurs consistently, patch the error to include the underlying cause (`fmt.Errorf(\"unable to tag NatGateway: %v\", err)`) to ease diagnosis"],"exampleFix":"// before\nreturn fmt.Errorf(\"unable to tag NatGateway\")\n// after\nreturn fmt.Errorf(\"unable to tag NatGateway: %v\", err)","handlingStrategy":"retry","validationCode":"// pre-check tag permissions\n_, err := ec2Client.CreateTags(ctx, &ec2.CreateTagsInput{Resources: []string{gatewayID}, Tags: toEC2Tags(tags)})\nif err != nil { return fmt.Errorf(\"tag pre-check failed: %w\", err) }","typeGuard":null,"tryCatchPattern":"err := applyCluster(ctx)\nif err != nil && strings.Contains(err.Error(), \"unable to tag NatGateway\") {\n  // idempotent: just re-run kops update cluster --yes after fixing IAM/throttling\n}","preventionTips":["Grant ec2:CreateTags in the kops IAM policy","Wrap AddAWSTags errors with the underlying cause for diagnosability","Re-run reconciliation after transient failures — tagging is idempotent"],"tags":["aws","ec2","tags","natgateway"],"backgroundTag":"tagging-failed","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"}