I created a cross-account AWS Transit Gateway VPC attachment and it was accepted, but the attachment transitioned to a "failed" state instead of "available."
Short description
A transit gateway VPC attachment that fails after acceptance is most commonly caused by a missing Transit Gateway Service-Linked Role (AWSServiceRoleForVPCTransitGateway) in the VPC owner's account. The IAM principal that created the attachment must have the iam:CreateServiceLinkedRole permission, or the Service-Linked Role must already exist in the account.
Resolution
Verify that the Service-Linked Role exists
Run the following command in the VPC owner's account:
aws iam get-role --role-name AWSServiceRoleForVPCTransitGateway
If the command returns a NoSuchEntity error, the Service-Linked Role doesn't exist. This is the most common cause of attachment provisioning failure.
Confirm in CloudTrail
Search CloudTrail for failed Service-Linked Role creation attempts:
aws cloudtrail lookup-events \
--lookup-attributes AttributeKey=EventName,AttributeValue=CreateServiceLinkedRole \
--start-time 2026-07-06T00:00:00Z \
--end-time 2026-07-07T00:00:00Z \
--output json
In the results, look for events where:
- The
errorCode is AccessDenied
- The
requestParameters contains transitgateway.amazonaws.com
This confirms that the transit gateway service attempted to create the role but the calling principal lacked permission.
Create the Service-Linked Role
Run the following command in the VPC owner's account to create the role:
aws iam create-service-linked-role --aws-service-name transitgateway.amazonaws.com
Note: This command only needs to be run once per account. After the role exists, all future transit gateway VPC attachment creations succeed regardless of iam:CreateServiceLinkedRole permissions on the calling principal.
Delete the failed attachment and create a new one
- Delete the failed attachment:
aws ec2 delete-transit-gateway-vpc-attachment \
--transit-gateway-attachment-id tgw-attach-0example1234
Note: Replace tgw-attach-0example1234 with your failed attachment ID.
- Confirm the deletion is complete:
aws ec2 describe-transit-gateway-vpc-attachments \
--transit-gateway-attachment-ids tgw-attach-0example1234 \
--query 'TransitGatewayVpcAttachments[0].State' \
--output text
Wait until the command returns deleted or an empty result.
- Create a new attachment:
aws ec2 create-transit-gateway-vpc-attachment \
--transit-gateway-id tgw-0example5678 \
--vpc-id vpc-0example9012 \
--subnet-ids subnet-0exampleabc subnet-0exampledef
Note: Replace the transit gateway ID, VPC ID, and subnet IDs with your values.
Prevent this issue in automated deployments
To avoid this failure in CloudFormation or Terraform deployments, create the Service-Linked Role as a dependency before the VPC attachment resource.
CloudFormation:
TGWServiceLinkedRole:
Type: AWS::IAM::ServiceLinkedRole
Properties:
AWSServiceName: transitgateway.amazonaws.com
TGWVpcAttachment:
Type: AWS::EC2::TransitGatewayAttachment
DependsOn: TGWServiceLinkedRole
Properties:
TransitGatewayId: !Ref TransitGateway
VpcId: !Ref MyVPC
SubnetIds:
- !Ref Subnet1
- !Ref Subnet2
Check for other causes of attachment failure
If the Service-Linked Role exists but the attachment still fails, verify the following:
- Only one attachment per VPC-to-TGW pair is allowed. Run
aws ec2 describe-transit-gateway-vpc-attachments and filter by your VPC and transit gateway to check for duplicate attachments.
- Subnets must have available IP addresses. The transit gateway requires at least one free IP address per subnet to create its elastic network interfaces.
- The RAM resource share must be accepted. For cross-account attachments, run
aws ram get-resource-share-invitations in the VPC owner's account and accept any pending invitations.
- The transit gateway attachment quota must not be exceeded. Check your service quota for transit gateway attachments.
Related information