-
-
Notifications
You must be signed in to change notification settings - Fork 4.3k
Description
Is there an existing issue for this?
- I have searched the existing issues
Current Behavior
🐛 Bug Description
CloudFormation deployments fail with artificial circular dependency errors when templates reference attributes that are immediately available after resource creation, such as !GetAtt RestApi.RootResourceId for API Gateway resources.
🔄 Expected vs Actual Behavior
Expected: CloudFormation templates with !GetAtt references to immediately available attributes (like RootResourceId, Arn, etc.) should deploy successfully, matching AWS CloudFormation behavior.
Actual: Deployment fails with circular dependency errors, even though the referenced attributes are available immediately after resource creation.
📋 Reproduction Steps
Minimal Reproduction Case
Create a CloudFormation template with API Gateway resources:
{
"AWSTemplateFormatVersion": "2010-09-09",
"Resources": {
"MyRestApi": {
"Type": "AWS::ApiGateway::RestApi",
"Properties": {
"Name": "TestAPI",
"Description": "Reproduction case for circular dependency bug"
}
},
"MyResource": {
"Type": "AWS::ApiGateway::Resource",
"Properties": {
"RestApiId": {"Ref": "MyRestApi"},
"ParentId": {"Fn::GetAtt": ["MyRestApi", "RootResourceId"]},
"PathPart": "items"
}
}
}
}Deploy with LocalStack:
awslocal cloudformation create-stack \
--stack-name test-circular-dependency \
--template-body file://test-template.jsonResult: Deployment fails with dependency resolution errors.
Real-World Impact
This issue affects:
- CDK-generated templates: CDK commonly generates templates with
!GetAtt RestApi.RootResourceIdpatterns - S3 bucket references: Templates accessing
Bucket.Arnimmediately after creation - Lambda function ARNs: Templates referencing
Function.Arnin dependent resources - Any resource with immediately available attributes
🔍 Root Cause Analysis
The issue occurs in get_attr_from_model_instance() function in template_deployer.py. The current implementation attempts dependency resolution for all !GetAtt references, even when:
- The target resource has already been created (has
PhysicalResourceId) - The requested attribute is already available in the resource's Properties
- The attribute was set by the resource provider during the
create()method
Technical Details
When API Gateway RestApi is created:
# In aws_apigateway_restapi.py create() method:
result = api.create_rest_api(**params) # AWS resource created
model["RestApiId"] = result["id"] # PhysicalResourceId set
# ... later in same method ...
model["RootResourceId"] = res["id"] # RootResourceId immediately availableHowever, the dependency resolver doesn't recognize that RootResourceId is immediately accessible and tries to resolve dependencies, creating artificial circular dependency loops.
💥 Impact
- High: Prevents deployment of common CloudFormation patterns
- Blocks CDK usage: Many CDK-generated templates fail to deploy
- Affects multiple services: API Gateway, S3, Lambda, DynamoDB, IAM resources
- Workaround complexity: Users must manually restructure templates to avoid the pattern
🌍 Environment
- LocalStack version: 4.10.1.dev7 (affects current stable releases)
- Platform: All platforms (Docker, local installation)
- Services affected: CloudFormation engine (impacts all AWS services)
📚 Additional Context
AWS Behavior
In real AWS CloudFormation, these attributes are available immediately and don't cause circular dependencies because:
- Resource providers set certain attributes synchronously during resource creation
- The CloudFormation engine recognizes immediately available attributes
- Dependency resolution is bypassed for attributes that don't require waiting
Similar Issues
This pattern appears in multiple scenarios:
- API Gateway:
RootResourceId,RestApiId - S3 Bucket:
Arn,DomainName,WebsiteURL - Lambda Function:
Arn - DynamoDB Table:
Arn - IAM Role/User:
Arn
🎯 Suggested Solution
The fix should:
- Detect when a resource has been created (has
PhysicalResourceId) - Check if the requested attribute exists in Properties (was set by resource provider)
- Return the attribute immediately without dependency resolution
- Be future-proof to handle new AWS services automatically
This approach leverages existing LocalStack patterns where resource providers set attributes in Properties during creation, requiring no hardcoded mappings or service-specific logic.
🔗 Related Resources
- LocalStack file:
localstack-core/localstack/services/cloudformation/engine/template_deployer.py - Function:
get_attr_from_model_instance() - AWS CloudFormation documentation: Fn::GetAtt function
- CDK patterns that generate affected templates
Labels: bug, cloudformation, high-priority, good-first-issue
Components: CloudFormation Engine, Template Deployer
Expected Behavior
No response
How are you starting LocalStack?
With a docker-compose file
Steps To Reproduce
How are you starting localstack (e.g., bin/localstack command, arguments, or docker-compose.yml)
docker run localstack/localstack
Client commands (e.g., AWS SDK code snippet, or sequence of "awslocal" commands)
awslocal s3 mb s3://mybucket
Environment
- OS:
- LocalStack:
LocalStack version:
LocalStack Docker image sha:
LocalStack build date:
LocalStack build git hash:Anything else?
No response