{"record":{"id":"ad67d3a9d7aae458","repo":"kubernetes/kops","slug":"vpc-id-is-required-when-egressonlyinternetgateway","errorCode":null,"errorMessage":"VPC ID is required when EgressOnlyInternetGateway is shared","messagePattern":"VPC ID is required when EgressOnlyInternetGateway is shared","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"upup/pkg/fi/cloudup/awstasks/egressonlyinternetgateway.go","lineNumber":77,"sourceCode":"\t}\n\n\tif len(response.EgressOnlyInternetGateways) != 1 {\n\t\treturn nil, fmt.Errorf(\"found multiple EgressOnlyInternetGateways matching tags\")\n\t}\n\tigw := response.EgressOnlyInternetGateways[0]\n\treturn &igw, nil\n}\n\nfunc (e *EgressOnlyInternetGateway) Find(c *fi.CloudupContext) (*EgressOnlyInternetGateway, error) {\n\tctx := c.Context()\n\tcloud := awsup.GetCloud(c)\n\n\trequest := &ec2.DescribeEgressOnlyInternetGatewaysInput{}\n\n\tshared := fi.ValueOf(e.Shared)\n\tif shared {\n\t\tif fi.ValueOf(e.VPC.ID) == \"\" {\n\t\t\treturn nil, fmt.Errorf(\"VPC ID is required when EgressOnlyInternetGateway is shared\")\n\t\t}\n\n\t\trequest.Filters = []ec2types.Filter{awsup.NewEC2Filter(\"attachment.vpc-id\", *e.VPC.ID)}\n\t} else {\n\t\tif e.ID != nil {\n\t\t\trequest.EgressOnlyInternetGatewayIds = []string{fi.ValueOf(e.ID)}\n\t\t} else {\n\t\t\trequest.Filters = cloud.BuildFilters(e.Name)\n\t\t}\n\t}\n\n\teigw, err := findEgressOnlyInternetGateway(ctx, cloud, request)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif eigw == nil {\n\t\treturn nil, nil\n\t}","sourceCodeStart":59,"sourceCodeEnd":95,"githubUrl":"https://github.com/kubernetes/kops/blob/4c8573c808a73d578c5eadc86d410646ea0b0d73/upup/pkg/fi/cloudup/awstasks/egressonlyinternetgateway.go#L59-L95","documentation":"kOps' EgressOnlyInternetGateway task's Find() performs discovery of an existing Egress-Only Internet Gateway in AWS EC2. When the task is marked as Shared (i.e. kOps adopts an existing gateway instead of creating one), Find() must filter the DescribeEgressOnlyInternetGateways call by VPC ID, so a missing VPC reference is a hard precondition. If e.VPC.ID is empty while Shared is true, the function returns this error before making any AWS API call.","triggerScenarios":"Calling Find() (directly or via the fitask machinery during kops update/apply) on an EgressOnlyInternetGateway task whose Shared field is true and whose VPC.ID pointer is nil or set to the empty string.","commonSituations":"A cluster spec where the VPC task reference is not wired up (e.g. hand-edited manifests, partial shared-VPC configuration, or lifecycle overrides that drop the VPC link); using kops against an existing VPC with shared Egress-Only gateways for IPv6 egress and forgetting to specify the VPC.","solutions":["Ensure the EgressOnlyInternetGateway task has a valid VPC reference set (e.VPC.ID must be a non-empty VPC ID) before applying.","Fix the cluster/spec so the VPC is defined (kops edit cluster / verify vpc field) and re-run kops update.","If the gateway is NOT meant to be shared, unset Shared so Find() uses the ID-based lookup path instead of the VPC filter."],"exampleFix":"// before\nshared := fi.ValueOf(e.Shared)\nif fi.ValueOf(e.VPC.ID) == \"\" { return nil, fmt.Errorf(\"VPC ID is required when EgressOnlyInternetGateway is shared\") }\n// after\n// caller must ensure the task is built with a real VPC, e.g.:\n// &awstasks.EgressOnlyInternetGateway{ Shared: fi.PtrTo(true), VPC: &awstasks.VPC{ID: fi.PtrTo(\"vpc-0abc123456789def0\")} }\n// set VPC.ID in the task construction so Find() can apply the attachment.vpc-id filter","handlingStrategy":"validation","validationCode":"if fi.ValueOf(task.Shared) && (task.VPC == nil || fi.ValueOf(task.VPC.ID) == \"\") {\n    return fmt.Errorf(\"EgressOnlyInternetGateway: Shared=true requires a non-empty VPC.ID\")\n}","typeGuard":"func hasVPCID(v *awstasks.VPC) bool {\n    return v != nil && fi.ValueOf(v.ID) != \"\"\n}","tryCatchPattern":null,"preventionTips":["Always set the VPC reference on shared cloud tasks in the cluster spec.","Validate the task graph before apply (kops update without --yes surfaces config errors first).","For shared VPC setups, keep vpc and subnets explicitly defined in the kOps manifest.","Review lifecycle overrides so they don't drop the VPC association."],"tags":["aws","ec2","vpc","ipv6","shared-resource"],"backgroundTag":"missing-required-vpc-id","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"}