floci-io/floci · error · AwsException
ValidationError
ValidationError
Error message
Property VpcId is required for AWS::EC2::VPCGatewayAttachment
What it means
ValidationError from the AWS::EC2::VPCGatewayAttachment provisioner when VpcId resolves to null/blank. Without the guard the attachment would be recorded with a null VpcId, which leaks into DescribeInternetGateways output and makes every later DetachInternetGateway on that gateway throw.
Source
Thrown at src/main/java/io/github/hectorvent/floci/services/cloudformation/provisioners/Ec2VpcGatewayAttachmentCfnProvisioner.java:47
private final Ec2Service ec2Service;
@Inject
public Ec2VpcGatewayAttachmentCfnProvisioner(Ec2Service ec2Service) {
this.ec2Service = ec2Service;
}
@Override
public Set<String> resourceTypes() {
return Set.of("AWS::EC2::VPCGatewayAttachment");
}
@Override
public void provision(StackResource r, JsonNode props, ProvisionContext ctx) {
String vpcId = ctx.resolveOptional(props, "VpcId");
if (vpcId == null || vpcId.isBlank()) {
// Without this the attachment lands with a null VpcId, which both shows up in
// DescribeInternetGateways and makes every later detach on that gateway throw.
throw new AwsException("ValidationError",
"Property VpcId is required for AWS::EC2::VPCGatewayAttachment", 400);
}
String igwId = ctx.resolveOptional(props, "InternetGatewayId");
String vgwId = ctx.resolveOptional(props, "VpnGatewayId");
boolean hasIgw = igwId != null && !igwId.isBlank();
boolean hasVgw = vgwId != null && !vgwId.isBlank();
if (hasIgw == hasVgw) {
throw new AwsException("ValidationError",
"AWS::EC2::VPCGatewayAttachment requires exactly one of "
+ "InternetGatewayId or VpnGatewayId", 400);
}
if (hasVgw) {
// There is no VPN gateway model to attach to and nothing DescribeVpnGateways
// could report afterwards, so recording a physical id would report
// CREATE_COMPLETE for an attachment that does not exist. Fail instead.
throw new AwsException("ValidationError",
"AWS::EC2::VPCGatewayAttachment with VpnGatewayId is not supported: "View on GitHub (pinned to 62ff490619)
Solutions
- Add an explicit VpcId to the resource: VpcId: !Ref Vpc (or the actual vpc-... id).
- If it references a parameter, ensure the deploy passes it: --parameters ParameterKey=VpcId,ParameterValue=vpc-....
- If it uses Fn::ImportValue, verify the export exists (ListExports) before deploying.
Example fix
# before
Resources:
Attach:
Type: AWS::EC2::VPCGatewayAttachment
Properties:
InternetGatewayId: !Ref Igw # VpcId missing
# after
Resources:
Attach:
Type: AWS::EC2::VPCGatewayAttachment
Properties:
VpcId: !Ref Vpc
InternetGatewayId: !Ref Igw Defensive patterns
Strategy: validation
Validate before calling
// Client-side template check before deploy
Object attach = templateAt("Resources/AttachGw/Properties");
if (attach == null || isBlank(((Map<?,?>) attach).get("VpcId"))) {
throw new IllegalArgumentException("VPCGatewayAttachment requires VpcId");
} Try / catch
catch AwsException/ValidationError from CreateStack; the stack event for the attachment resource carries the reason — fix the template, do not retry.
Prevention
- Run cfn-lint before deploying; required-property gaps are caught statically
- Pass every parameter a template declares, or give parameters defaults
- Prefer !Ref to a real AWS::EC2::VPC resource over string interpolation
When it happens
Trigger: A template declares AWS::EC2::VPCGatewayAttachment without a VpcId property, or with a VpcId that resolves to empty — e.g. !Ref on a parameter that was not passed, or !Sub on an unresolved import.
Common situations: Templates copied from AWS samples where VpcId comes from a parameter with no default and the emulator deploy omitted it; Fn::ImportValue of an export that does not exist (which resolves empty here rather than failing at resolution).
Understand the failure class
Background: ValidationError explained: why open-source libraries reject your input — file uploads, YAML manifests, unique fields, and query permissions — this error's family across 13 libraries.
Related errors
- ValidationError
- ValidationException
- ValidationError
- InvalidInput
- TLS enabled but no certificate provided and self-signed gene
AI-assisted analysis of floci-io/floci@62ff490619 (2026-08-14).
Data as JSON: /api/errors/69cebfecfa9ddc1d.
Report an issue: GitHub.