Fix: AWS CDK Not Working — Bootstrap Error, ROLLBACK_COMPLETE, and Deploy Failures
Quick Answer
How to fix AWS CDK errors — cdk bootstrap required, stack in ROLLBACK_COMPLETE, asset bundling failed, CLI/library version mismatch, VPC lookup failing, and cross-stack export conflicts.
The Error
You run cdk deploy and it fails immediately:
❌ Deployment failed: Error: This stack uses assets, so the toolkit stack must be deployed
to the environment (account 123456789012/us-east-1)Or your stack is stuck and every deploy attempt fails:
❌ MyStack failed: Error [ValidationError]: Stack:arn:aws:cloudformation:us-east-1:123456789012:stack/MyStack/xxx
is in ROLLBACK_COMPLETE state and can not be updated.Or bundling silently fails:
❌ Bundling did not produce any output. Check that content is written to /asset-output.Or your CDK v1 code imports break after upgrading:
Cannot find module '@aws-cdk/aws-s3' or its corresponding type declarations.Each of these has a specific fix. None requires rewriting your infrastructure code.
Why This Happens
CDK works in two phases: synthesis (cdk synth) converts your TypeScript/Python code into CloudFormation templates, then deployment (cdk deploy) uploads those templates and assets to AWS. Most errors fall into one of three categories:
- Environment not ready: AWS account/region hasn’t been bootstrapped, stack is in a bad state
- Asset pipeline broken: Docker isn’t running, versions are mismatched, or paths are wrong
- CDK model error: circular dependencies, cross-stack reference conflicts, lookup failures
Understanding which phase failed narrows the fix significantly.
Fix 1: “Toolkit Stack Must Be Deployed” — Run cdk bootstrap
CDK needs a set of AWS resources in each account/region before it can deploy stacks that use assets (Lambda code, Docker images, bundled files). These resources — an S3 bucket, ECR repository, and IAM roles — live in a CloudFormation stack called CDKToolkit.
The first time you deploy to any account or region, run bootstrap:
# Bootstrap the current account/region
cdk bootstrap
# Bootstrap a specific account and region
cdk bootstrap 123456789012/us-east-1
# Bootstrap with explicit credentials
cdk bootstrap --profile my-aws-profileWhen you need to re-bootstrap:
- First deployment to a new AWS account
- First deployment to a new region
- After a major CDK version upgrade that requires updated bootstrap resources
- When the
CDKToolkitstack was deleted
Check bootstrap status: Open the CloudFormation console and look for a stack named CDKToolkit. If it’s there and in CREATE_COMPLETE or UPDATE_COMPLETE state, bootstrap is done.
Permissions required to bootstrap: The IAM user or role running cdk bootstrap needs cloudformation:*, s3:*, ecr:*, iam:*, and ssm:*. In practice, AdministratorAccess is common for bootstrapping, though you can scope it down once the CDKToolkit stack exists.
Fix 2: Stack in ROLLBACK_COMPLETE State
CloudFormation puts a stack into ROLLBACK_COMPLETE when the initial creation failed and rolled back. The stack exists but contains no resources — and CloudFormation refuses to update it. You must delete it first:
# Delete the broken stack, then redeploy
cdk destroy MyStack
cdk deploy MyStackFor deeper detail on CloudFormation stack states and recovery, see AWS CloudFormation rollback complete. If cdk destroy fails (common when the stack has retained resources or deletion policies), delete it from the CloudFormation console directly:
- Go to the CloudFormation console
- Select the stuck stack
- Click Delete and wait for
DELETE_COMPLETE - Run
cdk deployagain
For UPDATE_ROLLBACK_FAILED (stack update failed and the rollback also failed): CloudFormation has a recovery mechanism specifically for this. In the console, choose Continue Update Rollback from the stack actions menu. This attempts to complete the rollback so the stack returns to a stable state.
Why stacks get stuck: A resource creation takes too long, an IAM permission is missing for one specific resource, a naming conflict with an existing AWS resource, or a dependency isn’t ready yet. The CloudFormation events tab shows the exact resource that failed — always check it before redeploying.
Fix 3: “Bundling Did Not Produce Any Output” — Docker Not Running
CDK uses Docker to bundle certain Lambda functions in a Linux environment (regardless of your OS). This ensures the bundled output is compatible with the Lambda runtime. If Docker isn’t running, bundling fails:
❌ Bundling did not produce any output. Check that content is written to /asset-output.Fix: Start Docker Desktop and retry cdk deploy. If Docker itself fails to start, see Docker daemon not running for platform-specific fixes.
CDK uses Docker for:
NodejsFunctionwith TypeScript sourcePythonFunctionfromaws-lambda-python-alpha- Any construct with a custom
bundling.image - Container image assets
Local bundling fallback — if you can’t run Docker (e.g., CI/CD with restricted permissions), configure local bundling:
import { NodejsFunction } from 'aws-cdk-lib/aws-lambda-nodejs';
new NodejsFunction(this, 'MyFunction', {
entry: 'src/handler.ts',
bundling: {
forceDockerBundling: false, // Try local bundling first
},
});Local bundling uses whatever node, esbuild, or python is available on the host. It’s faster for development but requires the correct toolchain to be installed locally.
In CI/CD pipelines: If you’re running CDK inside a Docker container (Docker-in-Docker), mount the Docker socket explicitly. GitHub Actions with setup-node and Docker pre-installed works without extra configuration, but some CI systems need explicit Docker socket access.
Fix 4: CLI and Library Version Mismatch
CDK has two separate packages:
aws-cdk— the CLI (cdk deploy,cdk synth,cdk diff)aws-cdk-lib— the construct library (the code you write)
If these are on incompatible versions, deployment fails with:
This CDK CLI is not compatible with the CDK library used by your application.
Please upgrade the CLI to the latest version.Or, if the CLI is newer than the library:
Maximum schema version supported is 43.x.x, but found 44.0.0Fix: Keep both at matching versions:
# Update the library
npm install aws-cdk-lib@latest
# Update the global CLI
npm install -g aws-cdk@latest
# Or use npx to avoid global version conflicts entirely
npx cdk deployPrefer npx cdk over cdk in project scripts. npx uses the locally installed version from node_modules/.bin/cdk, ensuring the CLI always matches the library version in your project.
// package.json — pin CLI to same version as library
{
"dependencies": {
"aws-cdk-lib": "2.150.0",
"constructs": "^10.0.0"
},
"devDependencies": {
"aws-cdk": "2.150.0"
},
"scripts": {
"deploy": "npx cdk deploy"
}
}Common Mistake: Installing aws-cdk globally with npm install -g aws-cdk and then forgetting to update it when you bump aws-cdk-lib in your project. The global CLI and the local library fall out of sync silently — your package.json shows the right version but cdk --version reports something older. Always use npx cdk in project scripts to avoid this entirely.
Note: CDK v2 uses monotone versioning — all AWS service modules are in a single aws-cdk-lib package with one version number. You don’t need to sync dozens of @aws-cdk/aws-* packages like you did in v1.
Fix 5: CDK v1 Import Errors in v2
The single most common error when upgrading from CDK v1 to v2:
// CDK v1 imports — no longer work in v2
import * as s3 from '@aws-cdk/aws-s3';
import * as lambda from '@aws-cdk/aws-lambda';
import { Construct } from '@aws-cdk/core';In CDK v2, all AWS service modules moved into aws-cdk-lib and Construct moved to the standalone constructs package:
// CDK v2 — correct imports
import { Construct } from 'constructs'; // Construct base class
import * as cdk from 'aws-cdk-lib'; // Core CDK classes
import * as s3 from 'aws-cdk-lib/aws-s3'; // S3 service
import * as lambda from 'aws-cdk-lib/aws-lambda'; // Lambda serviceComplete migration of a stack file:
// BEFORE (v1):
import * as cdk from '@aws-cdk/core';
import * as s3 from '@aws-cdk/aws-s3';
import * as lambda from '@aws-cdk/aws-lambda';
import { Construct } from '@aws-cdk/core';
export class MyStack extends cdk.Stack {
constructor(scope: Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);
new s3.Bucket(this, 'MyBucket');
}
}
// AFTER (v2):
import * as cdk from 'aws-cdk-lib';
import * as s3 from 'aws-cdk-lib/aws-s3';
import { Construct } from 'constructs'; // Different package
export class MyStack extends cdk.Stack {
constructor(scope: Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);
new s3.Bucket(this, 'MyBucket');
}
}After updating imports, remove all @aws-cdk/* packages from package.json and install aws-cdk-lib and constructs:
npm uninstall @aws-cdk/core @aws-cdk/aws-s3 @aws-cdk/aws-lambda # etc.
npm install aws-cdk-lib constructsFix 6: Context Lookup Failures — VPC Not Found
Vpc.fromLookup() queries your AWS account at synthesis time to find an existing VPC. If CDK can’t find it (wrong account, wrong region, wrong filters), synthesis fails or returns dummy-value:
// This fails if CDK can't query your account or no VPC matches the filter
const vpc = ec2.Vpc.fromLookup(this, 'ImportedVpc', {
vpcName: 'my-vpc'
});Error 1: Stack environment not specified
fromLookup() needs to know which account and region to query. If your stack doesn’t specify an environment, CDK uses environment-agnostic mode and can’t perform lookups:
// Fix: Specify environment on the stack
new MyStack(app, 'MyStack', {
env: {
account: process.env.CDK_DEFAULT_ACCOUNT,
region: process.env.CDK_DEFAULT_REGION
}
});Error 2: Stale cdk.context.json
CDK caches lookup results in cdk.context.json. If the VPC was modified or recreated after the cache was written, CDK uses the stale data:
# Clear context and re-run lookup
rm cdk.context.json
cdk synthOr delete just the specific key from cdk.context.json and re-run cdk synth.
Error 3: “All arguments to Vpc.fromLookup must be concrete”
If you pass a CloudFormation token (a value that’s only known at deploy time) to fromLookup(), synthesis fails because lookups happen at synthesis time, before deploy-time values exist:
// WRONG — env var used at synth time might be a token
const vpcId = process.env.VPC_ID!; // This is fine if it's a real value
const vpc = ec2.Vpc.fromVpcAttributes(this, 'Vpc', {
vpcId,
availabilityZones: ['us-east-1a', 'us-east-1b']
});
// If VPC_ID isn't a concrete value, use fromLookup with known tags instead
const vpc = ec2.Vpc.fromLookup(this, 'Vpc', {
tags: { 'environment': 'production' }
});Pro Tip: Commit cdk.context.json to source control. This ensures CI/CD pipelines don’t need live AWS access to perform lookups — they use the cached values from the last developer run. Only delete it locally when you need to re-query.
Fix 7: “Export Cannot Be Deleted” — Cross-Stack Reference Conflict
When Stack A exports a value used by Stack B, CloudFormation tracks that dependency. If you remove the reference from Stack B’s code but don’t deploy Stack B first, Stack A can’t delete its export:
Export MyStack:ExportsOutputFnGetAttMyBucketBucketArnXXXXXX cannot be deleted as it is
in use by AnotherStackThis requires a two-step deploy. Don’t redeploy Stack A yet:
# Step 1: Deploy Stack B first (removes the import of Stack A's export)
cdk deploy AnotherStack
# Step 2: Now deploy Stack A (export is no longer in use, safe to remove)
cdk deploy MyStackIf you need to add a cross-stack reference and the export doesn’t exist yet, deploy Stack A first:
cdk deploy StackA # Creates the export
cdk deploy StackB # Imports the exportAvoid this class of problem entirely: For values that need to be shared across stacks, consider using SSM Parameter Store or Secrets Manager instead of CloudFormation exports. These don’t create hard deployment-order dependencies.
Still Not Working?
Circular Dependencies Between Stacks
If cdk synth fails with “A cyclic dependency between stacks detected”, two stacks are referencing each other. The fix is to move shared resources to a third stack that both import:
// Stack A references Stack B, Stack B references Stack A — circular
// Fix: Extract shared resources to SharedStack
class SharedStack extends cdk.Stack {
public readonly bucket: s3.Bucket;
constructor(scope: Construct, id: string) {
super(scope, id);
this.bucket = new s3.Bucket(this, 'Shared');
}
}
class StackA extends cdk.Stack {
constructor(scope: Construct, id: string, shared: SharedStack) {
super(scope, id);
// Reference shared.bucket — no circular dep
}
}Lambda Runtime.ImportModuleError After Deploy
If cdk deploy succeeds but Lambda fails with Runtime.ImportModuleError: Cannot find module 'xyz', the dependency wasn’t bundled. See AWS Lambda import module error for the full breakdown of this error class, including layer-based dependency issues.
new NodejsFunction(this, 'MyFunction', {
entry: 'src/handler.ts',
bundling: {
// Explicitly bundle packages that aren't part of the Lambda runtime
nodeModules: ['my-custom-package'],
// Packages available in Lambda runtime (don't bundle these)
externalModules: ['@aws-sdk/*']
}
});AWS SDK v3 (@aws-sdk/*) is available in Node.js 18+ Lambda runtimes and should be in externalModules. Third-party packages must be in nodeModules or they’ll be missing at runtime.
AccessDenied During Deploy
CDK deploy uses IAM roles created during bootstrap. If someone deleted those roles or your credentials don’t have permission to assume them:
# Check which identity you're deploying as
aws sts get-caller-identity
# Check the bootstrap roles exist in IAM
aws iam list-roles | grep cdkThe role name pattern is cdk-XXXXX-deploy-role-ACCOUNTID-REGION. If it doesn’t exist, re-run cdk bootstrap.
Use --hotswap for Faster Development Iterations
For Lambda code changes during development, --hotswap bypasses CloudFormation and updates the function directly — seconds instead of minutes:
cdk deploy --hotswap # Direct update, skips CloudFormation for supported resources
cdk watch # Continuous: re-deploys with hotswap on file saveSupported: Lambda code/config, ECS container definitions, Step Functions state machines. Never use --hotswap in production — it creates drift between your CDK code and actual CloudFormation state.
Check CloudFormation Events for Specific Failures
When cdk deploy prints a generic failure, the actual cause is in the CloudFormation events. View them without leaving the terminal:
aws cloudformation describe-stack-events \
--stack-name MyStack \
--query 'StackEvents[?ResourceStatus==`CREATE_FAILED` || ResourceStatus==`UPDATE_FAILED`].[LogicalResourceId,ResourceStatusReason]' \
--output tableFor Terraform users moving to CDK, many Terraform state lock concepts apply similarly — CloudFormation has its own state management that can get stuck in the same ways.
Deployment failures that start succeeding in the AWS console but still fail via cdk deploy often indicate an AWS IAM AccessDeniedException — the CDK bootstrap roles may lack permission for a specific new resource type you added.
Solo developer based in Japan. Every solution is cross-referenced with official documentation and tested before publishing.
Was this article helpful?
Related Articles
Fix: SST Not Working — Deploy Failing, Bindings Not Linking, or Lambda Functions Timing Out
How to fix SST (Serverless Stack) issues — resource configuration with sst.config.ts, linking resources to functions, local dev with sst dev, database and storage setup, and deployment troubleshooting.
Fix: Deno PermissionDenied — Missing --allow-read, --allow-net, and Other Flags
How to fix Deno PermissionDenied (NotCapable in Deno 2) errors — the right permission flags, path-scoped permissions, deno.json permission sets, and the Deno.permissions API.
Fix: Fastify Not Working — 404, Plugin Encapsulation, and Schema Validation Errors
How to fix Fastify issues — route 404 from plugin encapsulation, reply already sent, FST_ERR_VALIDATION, request.body undefined, @fastify/cors, hooks not running, and TypeScript type inference.
Fix: Helm Not Working — Release Already Exists, Stuck Upgrade, and Values Not Applied
How to fix Helm 3 errors — release already exists, another operation is in progress, --set values not applied, nil pointer template errors, kubeVersion mismatch, hook failures, and ConfigMap changes not restarting pods.