Skip to content

Deploy large GraphQL APIs in CloudFormation-safe stack waves - #3484

Open
MarlonJD wants to merge 17 commits into
aws-amplify:mainfrom
MarlonJD:fix/auto-shard-transformer-stacks
Open

Deploy large GraphQL APIs in CloudFormation-safe stack waves#3484
MarlonJD wants to merge 17 commits into
aws-amplify:mainfrom
MarlonJD:fix/auto-shard-transformer-stacks

Conversation

@MarlonJD

@MarlonJD MarlonJD commented May 16, 2026

Copy link
Copy Markdown

Summary

This PR makes large generated GraphQL APIs deployable by splitting generated resources across CloudFormation-safe stack groups. It addresses the 1 MB template size limit, the 500 resources per stack limit, and the 2500 resources per CloudFormation operation limit.

Instead of keeping all generated nested stacks under one growing parent stack hierarchy, overflow generated stacks are promoted into ordered top-level stack groups. This keeps individual templates and stacks smaller, while also making CloudFormation process large APIs as multiple ordered stack operations.

Why

Large Gen2 GraphQL APIs can exceed multiple CloudFormation limits as the generated schema grows:

  • the 1 MB CloudFormation template size limit
  • the 500 resources per CloudFormation stack limit
  • the 2500 resources per CloudFormation create/update/delete operation limit

Reducing generated operations or removing secondary indexes can delay the issue, but it does not fix the underlying scaling problem. Large schemas still eventually generate too many AppSync resolvers, functions, data sources, IAM roles, DynamoDB tables, outputs, and nested stacks for a single generated stack layout.

The 500-resource stack limit and 1 MB template limit require generated resources to be split into smaller stacks. The 2500-resource operation limit also means that simply creating more nested stacks is not enough if they all remain under the same parent stack hierarchy. CloudFormation can still process the whole nested hierarchy as one oversized operation.

Addresses:

Problems found during validation

While testing this with a large Gen2 schema, a few additional issues appeared:

  1. Generated model stacks could exceed CloudFormation's 500-resource stack limit and/or the 1 MB template size limit.
  2. Overflow generated stacks could not stay inside the same nested hierarchy, because that still risks the 2500-resource operation limit.
  3. Moving overflow stacks into top-level CDK stacks meant getGeneratedResources could no longer discover all generated constructs unless discovery was extended.
  4. Top-level stack groups import the API id from the root stack, which made some model output Export.Name values invalid because CloudFormation export names cannot depend on Fn::ImportValue, Fn::GetAtt, or Fn::GetAZs.
  5. DynamoDB table configuration parameters needed to be available in the new top-level stack groups as well as the original nested stacks.
  6. @function can create FunctionDirectiveStack before the stack manager later reuses that same stack for automatic sharding, which meant the stack could miss the default-stack metadata used by adaptive sizing.

How this works

This change splits large generated APIs in two layers.

First, the transformer stack manager now auto-shards generated resources by an estimated resource budget. Explicit stack mappings are still respected, but unmapped/generated resources are distributed across additional generated stacks before a single stack grows too large.

The budget intentionally leaves headroom below CloudFormation's 500-resource stack limit because some logical transformer resources synthesize into multiple CloudFormation resources. For example, pipeline resolvers and Lambda data sources count as more than one estimated resource.

This helps keep each generated stack below both:

  • the 500 resources per stack limit
  • the 1 MB template size limit

Second, the nested stack provider now keeps the first batch of generated nested stacks under the data stack, then promotes overflow batches into separate top-level CDK stacks named like:

  • AmplifyGraphqlApiStackGroup1
  • AmplifyGraphqlApiStackGroup2
  • AmplifyGraphqlApiStackGroup3

Each group contains a bounded number of generated nested stacks. The groups are chained with dependencies:

root stack -> group 1 -> group 2 -> group 3

This makes CloudFormation deploy them as separate ordered stack operations instead of one oversized nested-stack operation. That is the part that addresses the 2500-resource operation limit.

Additional fixes

  • Added metadata to generated top-level stack groups so generated-resource discovery can find constructs inside them.
  • Updated getGeneratedResources to walk both the original generated scope and the generated top-level stack groups.
  • Added a guard for model output export names. If the resolved export name would depend on a forbidden CloudFormation reference, the output value is still emitted but the exportName is omitted.
  • Added DynamoDB parameter passthrough support for the generated top-level stack groups.
  • Added default-stack metadata when an existing generated stack later participates in automatic sharding, covering pre-created stacks such as FunctionDirectiveStack.

Validation

  • git diff --check
  • PATH=/Users/marlonjd/.nvm/versions/node/v20.18.3/bin:$PATH yarn workspace @aws-amplify/graphql-api-construct test nested-stack-provider.test.ts construct-exports.test.ts --runInBand --coverage=false
  • PATH=/Users/marlonjd/.nvm/versions/node/v20.18.3/bin:$PATH yarn workspace @aws-amplify/graphql-model-transformer test dynamo-model-resource-generator.test.ts --runInBand --coverage=false
  • PATH=/Users/marlonjd/.nvm/versions/node/v20.18.3/bin:$PATH yarn workspace @aws-amplify/graphql-transformer-core test stack-manager.test.ts --runInBand --coverage=false

I also validated this against a real Gen2 sandbox deployment with a 200 parent / 200 child model schema in eu-central-1.

The deployment created 8 top-level GraphQL API stack groups and completed successfully without hitting:

  • the 1 MB template size limit
  • the 500 resources per stack limit
  • the 2500 resources per CloudFormation operation limit
  • the invalid Export.Name validation error

The smoke-test sandbox was deleted afterwards, and no matching CloudFormation stacks remained.

Trying this before merge

A preview build of this PR is available on npm for testing before it is merged.

For Gen2 projects, use the full override set below so the local project and bundled transformer packages resolve to the same preview build:

{
  "overrides": {
    "@aws-amplify/data-construct": "npm:@marlonjd/data-construct@1.17.4-auto-shard-transformer-stacks.6",
    "@aws-amplify/graphql-api-construct": "npm:@marlonjd/graphql-api-construct@1.21.4-auto-shard-transformer-stacks.7",
    "@aws-amplify/graphql-transformer": "npm:@marlonjd/graphql-transformer-stack-limits@2.4.2-stack-limits.2",
    "@aws-amplify/graphql-transformer-core": "npm:@marlonjd/graphql-transformer-core-stack-limits@3.5.1-stack-limits.6",
    "@aws-amplify/graphql-transformer-interfaces": "npm:@marlonjd/graphql-transformer-interfaces-stack-limits@4.3.0-stack-limits.2",
    "@aws-amplify/graphql-model-transformer": "npm:@marlonjd/graphql-model-transformer-stack-limits@3.4.1-stack-limits.2",
    "@aws-amplify/graphql-relational-transformer": "npm:@marlonjd/graphql-relational-transformer-stack-limits@3.1.13-stack-limits.4"
  }
}

Then reinstall and deploy from the local project:

npm install
npx ampx sandbox

For lower-level testing, the individual patched packages are also published:

{
  "overrides": {
    "@aws-amplify/data-construct": "npm:@marlonjd/data-construct@1.17.4-auto-shard-transformer-stacks.6",
    "@aws-amplify/graphql-api-construct": "npm:@marlonjd/graphql-api-construct@1.21.4-auto-shard-transformer-stacks.7",
    "@aws-amplify/graphql-transformer": "npm:@marlonjd/graphql-transformer-stack-limits@2.4.2-stack-limits.2",
    "@aws-amplify/graphql-transformer-core": "npm:@marlonjd/graphql-transformer-core-stack-limits@3.5.1-stack-limits.6",
    "@aws-amplify/graphql-transformer-interfaces": "npm:@marlonjd/graphql-transformer-interfaces-stack-limits@4.3.0-stack-limits.2",
    "@aws-amplify/graphql-model-transformer": "npm:@marlonjd/graphql-model-transformer-stack-limits@3.4.1-stack-limits.2",
    "@aws-amplify/graphql-relational-transformer": "npm:@marlonjd/graphql-relational-transformer-stack-limits@3.1.13-stack-limits.4"
  }
}

Make sure ampx is resolved from the local project dependencies. Running a globally installed ampx may bypass these overrides.

Additional Validation

Latest @function field-auth edge-case update was validated with:

  • git diff --check
  • env npm_config_devdir=/private/tmp/node-gyp YARN_CACHE_FOLDER=/Users/marlonjd/.cache/yarn corepack yarn workspace @aws-amplify/graphql-transformer-core test stack-manager.test.ts --runInBand --coverage=false
  • env npm_config_devdir=/private/tmp/node-gyp YARN_CACHE_FOLDER=/Users/marlonjd/.cache/yarn corepack yarn workspace @aws-amplify/graphql-function-transformer test amplify-graphql-function-transformer.test.ts --runInBand --coverage=false --silent
  • env npm_config_devdir=/private/tmp/node-gyp YARN_CACHE_FOLDER=/Users/marlonjd/.cache/yarn corepack yarn workspace @aws-amplify/graphql-api-construct test adaptive-sizer.test.ts --runInBand --coverage=false
  • env npm_config_devdir=/private/tmp/node-gyp YARN_CACHE_FOLDER=/Users/marlonjd/.cache/yarn corepack yarn workspace amplify-graphql-api-construct-tests jest function-directive-stack-limits.test.ts --runInBand --coverage=false
  • env npm_config_devdir=/private/tmp/node-gyp YARN_CACHE_FOLDER=/Users/marlonjd/.cache/yarn corepack yarn workspace amplify-graphql-api-construct-tests build-tests
  • Preview package tarball spot-check: the published API/Data construct bundles include the updated @aws-amplify/graphql-transformer-core stack-manager.js with addDefaultStackNameMetadata.
  • Clean npm preview Data construct verification with @marlonjd/data-construct@1.17.4-auto-shard-transformer-stacks.5, @marlonjd/graphql-api-construct@1.21.4-auto-shard-transformer-stacks.5, and @marlonjd/graphql-transformer-core-stack-limits@3.5.1-stack-limits.5 synthesized the reported @function + IAM field-auth shape into two FunctionDirectiveStack templates: 300 resources and 216 resources.
  • Regression check with the older stack-limits.4 Data construct preview reproduced the failure: one FunctionDirectiveStack with 516 resources, exceeding the 500-resource CloudFormation stack limit.
  • Published preview packages:
    • @marlonjd/graphql-transformer-core-stack-limits@3.5.1-stack-limits.6 (stack-limits)
    • @marlonjd/graphql-api-construct@1.21.4-auto-shard-transformer-stacks.7 (auto-shard-transformer-stacks)
    • @marlonjd/data-construct@1.17.4-auto-shard-transformer-stacks.6 (auto-shard-transformer-stacks)

The earlier edge-case hardening update was validated with:

  • git diff --check
  • yarn test stack-manager.test.ts --runInBand --coverage=false in packages/amplify-graphql-transformer-core
  • yarn test nested-stack-provider.test.ts adaptive-sizer.test.ts --runInBand --coverage=false in packages/amplify-graphql-api-construct
  • yarn test resources.test.ts --runInBand --coverage=false in packages/amplify-graphql-api-construct
  • yarn jest commands.test.ts --runInBand --coverage=false --reporters=default --env=node --testRunner=jest-circus/runner in packages/amplify-graphql-api-construct-tests
  • yarn jest --runTestsByPath scripts/__tests__/verify-construct-dependencies.test.ts --runInBand --coverage=false --reporters=default --env=node --testRunner=jest-circus/runner --config jest.config.base.js --roots scripts --globals '{"ts-jest":{"diagnostics":false,"isolatedModules":true}}'
  • yarn build in the touched transformer/API construct packages, including amplify-graphql-transformer-interfaces, amplify-graphql-transformer-core, amplify-graphql-transformer, amplify-graphql-api-construct, and the legacy graphql-transformer-core dependency needed by test builds
  • yarn build-tests in packages/amplify-graphql-api-construct-tests
  • yarn extract-api in amplify-graphql-transformer-interfaces, amplify-graphql-transformer-core, amplify-graphql-transformer, and amplify-graphql-api-construct
  • yarn verify-construct-dependencies
  • Preview override consumer smoke test in a clean temporary npm project: npm install resolved the changed @aws-amplify/* packages to the @marlonjd/*-stack-limits aliases, including the .4 data construct, GraphQL API construct, transformer core, and relational transformer preview packages.
  • Preview construct smoke test: importing @aws-amplify/data-construct with the override set and synthesizing a public Todo @model schema completed successfully (15 synthesized root resources).
  • Full preview E2E customer-project deploy in AWS eu-central-1 using stack prefix AmplifyPreviewE2EStackLimits-20260520-03: deployed both default DynamoDB and AMPLIFY_TABLE strategies with owner/groups auth, relations, secondary indexes, grouped grants, adaptive grouped nested stacks, and Lambda grant targets.
  • Full preview E2E synth/assertion pass for the same project used E2E_OPERATION_BUDGET=450, produced 29 nested stacks across 33 templates, verified max template resource count was 48, and verified generated root/group operation resource counts stayed below the 2500 hard limit.
  • The full preview E2E stack was destroyed with npx cdk destroy --all --force; follow-up CloudFormation list-stacks returned no active or failed stacks for the prefix, and both AppSync APIs returned NotFound.
  • The first two full E2E attempts caught fixture-only dependency serialization issues around AMPLIFY_TABLE and grouped nested stacks; after narrowing the fixture serialization to root-parent operations and keeping AmplifyTableManager first, the final deploy/destroy passed.
  • Bundled runtime spot-check: the nested transformer packages inside the preview graphql-api-construct bundle include the patched StackManagerOptions and estimatedResourceCount APIs.

The resources.test.ts run also covers grouped grant behavior for both default DynamoDB tables and AMPLIFY_TABLE, asserts no grouped table grant policy depends on Fn::ImportValue/nested outputs, verifies index ARN grants remain present, checks grouped stream grants do not fabricate a stream ARN, and asserts generated direct/group operation CfnResource counts stay below the 2500 hard limit.

Update-safety readiness refresh

After the previous 399/51/51/25 validation snapshot, I tightened this PR around update safety and review readiness rather than broadening the feature surface.

Safety decisions made

  • Existing stateful/root nested stacks keep their original parent across baseline -> expanded schema updates.
  • Existing AWS::DynamoDB::Table and Custom::AmplifyDynamoDBTable resources are kept out of generated stack groups.
  • Existing API-scoped AppSync resources stay pinned, including resolvers, data sources, functions, schemas, and API-level custom resources.
  • Newly generated overflow resources can move only when the baseline source proves they were absent from the successful baseline.
  • AppSync resources that cannot be classified as safely new fail closed with an actionable diagnostic instead of silently re-parenting.
  • Both CloudFormation limits are enforced: 500 resources per nested stack and 2500 resources per operation.
  • Shared generated stack discovery logic was centralized in generated-stack-helpers.ts and reused by adaptive sizing, construct exports, nested stack provider, and DynamoDB table wrapper paths.

RED/GREEN evidence

  • RED: existing root/stateful nested stack preservation test showed ExistingModelC moving unexpectedly.
    GREEN: root nested stack preservation now keeps existing stateful stacks under the original parent.
  • RED: pinned AppSync/API-scoped resource placement test expected ConnectionStack and observed ConnectionStack2.
    GREEN: stack manager now uses pinned, movable, and unclassified-api-scoped placement classification and fails closed for ambiguous API-scoped resources.
  • RED: adaptive sizing did not fail when a generated nested stack exceeded 500 resources.
    GREEN: adaptive sizing now enforces both the 500-resource nested stack cap and the 2500-operation cap.
  • RED: package smoke initially failed on the local npm cache permission issue.
    GREEN: the same package smoke passed with npm cache redirected to /private/tmp/amplify-npm-cache.

Verification run after the refresh

  • git diff --check
  • @aws-amplify/graphql-api-construct focused tests:
    • nested-stack-provider.test.ts
    • adaptive-sizer.test.ts
    • update-safety-placement.test.ts
    • resources.test.ts
    • construct-exports.test.ts
  • @aws-amplify/graphql-transformer-core:
    • stack-manager.test.ts
  • @aws-amplify/graphql-function-transformer:
    • amplify-graphql-function-transformer.test.ts
  • @aws-amplify/graphql-auth-transformer:
    • get-scope-for-field.test.ts
  • Construct package tests:
    • function-directive-stack-limits.test.ts
    • commands.test.ts
    • update-safety-change-set.test.ts
  • Build/extract:
    • amplify-graphql-api-construct-tests build-tests
    • @aws-amplify/graphql-transformer-interfaces build
    • @aws-amplify/graphql-transformer-core build
    • @aws-amplify/graphql-transformer build
    • @aws-amplify/graphql-api-construct build
    • corepack yarn extract-api across 25 packages
  • Local package smoke:
    • @aws-amplify/graphql-api-construct package
    • local Verdaccio publish smoke
    • clean consumer install and npx cdk synth --app "node app.js"
  • AWS update-safety smoke:
    • baseline deploy -> expanded schema change-set -> assertions -> destroy
    • stack prefix: AmplifyPreviewUpdateSafety-20260619-local
    • region: eu-central-1
    • cleanup check returned no active stacks for the prefix

Preview package

  • Published latest package-level preview:
    • @marlonjd/graphql-api-construct@1.21.4-auto-shard-transformer-stacks.7
    • dist-tag: auto-shard-transformer-stacks
  • latest was not changed and remains 1.21.4-auto-shard-transformer-stacks.4.

Not run

  • Full cloud e2e was not triggered because corepack yarn cloud-e2e requires scripts/.env e2e account configuration, and that file was not present locally.

@MarlonJD
MarlonJD requested a review from a team as a code owner May 16, 2026 09:18
@MarlonJD MarlonJD changed the title fix: prevent generated GraphQL stacks from hitting CloudFormation limits Keep large GraphQL APIs below CloudFormation generated-stack limits May 16, 2026
@MarlonJD MarlonJD changed the title Keep large GraphQL APIs below CloudFormation generated-stack limits Deploy large GraphQL APIs in CloudFormation-safe stack waves May 16, 2026
@MarlonJD

Copy link
Copy Markdown
Author

PTAL @svidgen

@Tryanium

Copy link
Copy Markdown

Hi team any news on this? I think this fix would solve my issue as well!

@MarlonJD
MarlonJD requested a review from a team as a code owner May 20, 2026 09:28
@MarlonJD

Copy link
Copy Markdown
Author

I also added a standalone real Amplify Gen2 repro project that reviewers can use to validate the published preview packages end-to-end:

https://github.com/MarlonJD/amplify-gen2-stack-sharding-repro

The sample project installs the patched packages through npm aliases/overrides:

  • @aws-amplify/data-construct -> @marlonjd/data-construct@1.17.4-auto-shard-transformer-stacks.1
  • @aws-amplify/graphql-api-construct -> @marlonjd/graphql-api-construct@1.21.4-auto-shard-transformer-stacks.1

It is a real Amplify Gen2 backend with one Todo model for runtime smoke testing plus MODEL_COUNT generated models to force a large transformer output. MODEL_COUNT defaults to 80.

Validation flow:

nvm use
npm install
npm run verify:packages
AWS_REGION=eu-central-1 MODEL_COUNT=80 npm run sandbox
npm run test:graphql
npm run sandbox:delete

What this validates:

  • A real Amplify Gen2 project can resolve and install the published preview construct packages.
  • @aws-amplify/data-construct resolves to the patched @marlonjd/data-construct package.
  • The patched data construct depends on @marlonjd/graphql-api-construct@1.21.4-auto-shard-transformer-stacks.1.
  • A large schema can synthesize/deploy through ampx sandbox with transformer stack auto-sharding enabled.
  • The deployed AppSync API works at runtime via createTodo and listTodos.
  • The sandbox can be deleted cleanly after validation.

I also verified locally that the repro project passes:

npm run verify:packages
npx tsc --noEmit
npm ls @aws-amplify/data-construct @aws-amplify/graphql-api-construct @marlonjd/graphql-api-construct --all

@sotolucas

Copy link
Copy Markdown

Hey @MarlonJD , looks promising.
Still I'm wondering how'd this work when applying this update to existing applications that will now enter in "shard" mode. Wouldn't this break existing data resources?

@MarlonJD

Copy link
Copy Markdown
Author

Thanks for raising this. I ran a bit more validation after your comment.

What I verified so far:

  • A local migration-focused synth probe with a 60-model public @model schema using this PR.
  • The synth produced 60 DynamoDB tables: 54 stayed in the direct generated stacks, and 6 moved under a new top-level AmplifyGraphqlApiStackGroup.
  • The focused test coverage still passes:
    • resources.test.ts: 30/30 passed
    • nested-stack-provider.test.ts: 5/5 passed
    • adaptive-sizer.test.ts: 3/3 passed
    • stack-manager.test.ts: 7/7 passed

The existing tests cover the fresh large-deploy path, grouped default DynamoDB tables, grouped AMPLIFY_TABLE, grouped grants without Fn::ImportValue/nested output dependencies, relationship output limits, adaptive sizing, stack grouping, and explicit stack mapping precedence.

That said, I agree the existing-app upgrade path needs one more explicit validation before we call it safe. The synth probe shows that some existing generated tables could move into a new stack group once sharding kicks in, so the next check should be a real deploy -> upgrade-to-preview -> CloudFormation change set/deploy test to verify that existing DynamoDB tables are not replaced or deleted.

Do you have a preferred migration scenario you’d like me to prioritize for that validation?

@sotolucas

Copy link
Copy Markdown

@MarlonJD thanks for the update!
None at all. LMK if I can help in any way.

@MarlonJD

MarlonJD commented Jun 1, 2026

Copy link
Copy Markdown
Author

@MarlonJD thanks for the update! None at all. LMK if I can help in any way.

Thanks! The most useful help would be validating the existing-app upgrade path on a real Gen2 project, ideally in a non-production sandbox or copied environment.

What I’m trying to confirm is whether applying the preview packages to an existing deployed app causes any unsafe CloudFormation changes, especially:

  • AWS::DynamoDB::Table replacement or deletion
  • AppSync API replacement
  • failed nested stack moves when sharding starts
  • broken runtime CRUD/list queries after deploy

If you have a large enough existing project, even a sanitized/internal test copy would help. The ideal flow would be:

  1. Start from the current stable Amplify packages and an already-deployed sandbox.
  2. Add the preview package overrides from this PR/repro.
  3. Run npm install.
  4. Run npx ampx sandbox in a disposable/non-prod environment.
  5. Check the CloudFormation change set/deploy output for DynamoDB table replacements/deletions.
  6. Smoke test a few existing models after deploy.

If you can share results, the most helpful details would be the approximate schema shape: number of models, indexes, relationships, auth rules, whether you use AMPLIFY_TABLE, and any sanitized CloudFormation change actions involving DynamoDB/AppSync resources. No need to share proprietary schema.

@RestingState

Copy link
Copy Markdown

Hope this will be resolved ASAP. Have similar problem and waiting on solution

@RestingState

Copy link
Copy Markdown

@MarlonJD I tried your preview.

I first tried to run it with only the number of resources in FunctionDirective to be below 500 limit (my stack had 475 after the removal of some queries/mutations). The sandbox deployment went successful.

Then I tried to return removed queries/mutations, where the limit hits and got

10:39:31 PM [ERROR] [BackendBuildError] Unable to deploy due to CDK Assembly Error
  ∟ Caused by: [AssemblyError] Assembly builder failed
    ∟ Caused by: [TooManyResourcesInStack] Number of resources in stack 'amplify-*****/data/*****/FunctionDirectiveStack': 517 is greater than allowed maximum of 500: AWS::IAM::Role (86), AWS::IAM::Policy (86), AWS::AppSync::DataSource (86), AWS::AppSync::FunctionConfiguration (172), AWS::AppSync::Resolver (86), AWS::CDK::Metadata (1)
Resolution: Check the Caused by error and fix any issues in your backend code

@RestingState

RestingState commented Jun 11, 2026

Copy link
Copy Markdown

Also want to point out that the name of the autogenerated function directive stack by the amplify is
amplify-<backend-name>-<identifier>-sandbox-9e-<backend-name>FunctionDirectiveStac-1N3F04VB1HBAP

Check out the end of the name, it's FunctionDirectiveStac instead of FunctionDirectiveStack

I suppose the reason for this is the stack name became too large so it's slightly shortened by the amplify framework.
is taken as amplifyData if not were provided in amplify/data/resource.ts or if provided then the name

image

Hope it will be useful for you

@MarlonJD

Copy link
Copy Markdown
Author

Thanks for the extra detail on the physical nested stack name. I checked this path too: the deployed FunctionDirectiveStac suffix appears to be the physical CloudFormation stack name being shortened because the generated name is long. The synthesized construct/template identity still uses FunctionDirectiveStack, and the fix does not rely on that deployed physical stack name.

I also reproduced the reported Data construct shape with 86 @function root fields plus IAM field auth. With the older *-stack-limits.4 Data construct preview, the same shape fails with one FunctionDirectiveStack containing 516 resources. With the updated preview packages below, it synthesizes into two FunctionDirectiveStack templates with 300 and 216 resources, both under the 500-resource stack limit.

I added e2e coverage for this path in this PR and validated the published npm preview packages in a clean project. Could you retry the current PR preview with this override set?

{
  "overrides": {
    "@aws-amplify/data-construct": "npm:@marlonjd/data-construct@1.17.4-auto-shard-transformer-stacks.5",
    "@aws-amplify/graphql-api-construct": "npm:@marlonjd/graphql-api-construct@1.21.4-auto-shard-transformer-stacks.5",
    "@aws-amplify/graphql-transformer": "npm:@marlonjd/graphql-transformer-stack-limits@2.4.2-stack-limits.2",
    "@aws-amplify/graphql-transformer-core": "npm:@marlonjd/graphql-transformer-core-stack-limits@3.5.1-stack-limits.5",
    "@aws-amplify/graphql-transformer-interfaces": "npm:@marlonjd/graphql-transformer-interfaces-stack-limits@4.3.0-stack-limits.2",
    "@aws-amplify/graphql-model-transformer": "npm:@marlonjd/graphql-model-transformer-stack-limits@3.4.1-stack-limits.2",
    "@aws-amplify/graphql-relational-transformer": "npm:@marlonjd/graphql-relational-transformer-stack-limits@3.1.13-stack-limits.4"
  }
}

After updating overrides, please reinstall/regenerate the lockfile and run npx ampx sandbox from the local project so ampx resolves through the project dependencies.

@RestingState

Copy link
Copy Markdown

Great. I will try it right now

@RestingState

RestingState commented Jun 11, 2026

Copy link
Copy Markdown

@MarlonJD Still got

12:30:43 AM [ERROR] [BackendBuildError] Unable to deploy due to CDK Assembly Error
  ∟ Caused by: [AssemblyError] Assembly builder failed
    ∟ Caused by: [TooManyResourcesInStack] Number of resources in stack 'amplify-*****-sandbox-9eae5d73f2/data/*****/FunctionDirectiveStack': 517 is greater than allowed maximum of 500: AWS::IAM::Role (86), AWS::IAM::Policy (86), AWS::AppSync::DataSource (86), AWS::AppSync::FunctionConfiguration (172), AWS::AppSync::Resolver (86), AWS::CDK::Metadata (1)
Resolution: Check the Caused by error and fix any issues in your backend code

Did the clean install. Removed node_modules + lock file. Added overrides that you provided in the comment above. Runned npm i + sandbox

@RestingState

Copy link
Copy Markdown

I may try to lower the number of operations below the limit; run successful sandbox; add operations above the limit; try to run sandbox once again

@RestingState

Copy link
Copy Markdown

Rerun the logic as specified in the comment above and the error persists.
When number of resources below the limit, it deploys good, but when limit hits I get the same error

@MarlonJD

Copy link
Copy Markdown
Author

Thanks for retrying and for the exact error. I rechecked this in a fresh Gen2-style project using the same override set from my previous comment, with @aws-amplify/backend@1.23.0 and @aws-amplify/backend-cli@1.8.3.

In that clean install, a raw schema with 86 root @function fields plus IAM field auth synthesizes without the assembly error. The generated FunctionDirectiveStack output is split into two nested templates:

  • FunctionDirectiveStack: 301 resources
  • FunctionDirectiveStack2: 217 resources
  • total across both: 518 resources

So the remaining failure you are seeing looks most likely like the sandbox process is still resolving an older/unpatched construct tree somewhere, rather than this exact preview package set being applied to the running ampx process.

Could you run these from the same project directory where npx ampx sandbox fails and paste the output?

npm ls @aws-amplify/backend @aws-amplify/backend-cli @aws-amplify/backend-data @aws-amplify/data-construct @aws-amplify/graphql-api-construct @aws-amplify/graphql-transformer-core --all
node -e 'const fs=require("fs"); const names=["@aws-amplify/data-construct","@aws-amplify/graphql-api-construct","@aws-amplify/graphql-transformer-core","@aws-amplify/data-construct/node_modules/@aws-amplify/graphql-transformer-core","@aws-amplify/graphql-api-construct/node_modules/@aws-amplify/graphql-transformer-core"]; for (const name of names) { try { const path=require.resolve(name + "/package.json"); const p=require(path); console.log(name, "=>", p.name, p.version, path); } catch (e) { console.log(name, "MISSING", e.code); } } for (const name of ["@aws-amplify/graphql-transformer-core/lib/transformer-context/stack-manager.js","@aws-amplify/data-construct/node_modules/@aws-amplify/graphql-transformer-core/lib/transformer-context/stack-manager.js","@aws-amplify/graphql-api-construct/node_modules/@aws-amplify/graphql-transformer-core/lib/transformer-context/stack-manager.js"]) { try { const path=require.resolve(name); const src=fs.readFileSync(path,"utf8"); console.log("STACK_MANAGER", name, { path, patched: src.includes("getStackNameWithinResourceBudget"), autoLimit: src.includes("DEFAULT_AUTO_STACK_RESOURCE_ESTIMATE = 400") }); } catch (e) { console.log("STACK_MANAGER", name, "MISSING", e.code); } }'

One note: the bundled nested @aws-amplify/graphql-transformer-core package may still print package version 3.5.1; that part alone is not enough to prove it is stale. The important bit is whether the STACK_MANAGER ... patched: true, autoLimit: true checks show up for the copies under @aws-amplify/data-construct and @aws-amplify/graphql-api-construct.

Also, please use the project-local CLI path when retrying, for example:

npx --no-install ampx sandbox

That avoids accidentally running a freshly downloaded/global ampx against a different dependency tree.

@RestingState

Copy link
Copy Markdown

@MarlonJD
npm ls returned

├─┬ @aws-amplify/backend-cli@1.8.3
│ │ └─┬ @aws-amplify/schema-generator@1.4.1
│ │   └─┬ @aws-amplify/graphql-schema-generator@0.11.14
│ │     └── @aws-amplify/graphql-transformer-core@3.5.1
│ └─┬ @aws-amplify/backend@1.23.0
│   └─┬ @aws-amplify/backend-data@1.7.0
│     └─┬ @aws-amplify/data-construct@1.17.3
│       ├─┬ @aws-amplify/graphql-api-construct@1.21.3
│       │ ├─┬ @aws-amplify/graphql-auth-transformer@4.2.7
│       │ │ └── @aws-amplify/graphql-transformer-core@3.5.1 deduped
│       │ ├─┬ @aws-amplify/graphql-conversation-transformer@1.1.14
│       │ │ └── @aws-amplify/graphql-transformer-core@3.5.1 deduped
│       │ ├─┬ @aws-amplify/graphql-default-value-transformer@3.1.16
│       │ │ └── @aws-amplify/graphql-transformer-core@3.5.1 deduped
│       │ ├─┬ @aws-amplify/graphql-function-transformer@3.1.18
│       │ │ └── @aws-amplify/graphql-transformer-core@3.5.1 deduped
│       │ ├─┬ @aws-amplify/graphql-generation-transformer@1.2.6
│       │ │ └── @aws-amplify/graphql-transformer-core@3.5.1 deduped
│       │ ├─┬ @aws-amplify/graphql-http-transformer@3.0.21
│       │ │ └── @aws-amplify/graphql-transformer-core@3.5.1 deduped
│       │ ├─┬ @aws-amplify/graphql-index-transformer@3.1.1
│       │ │ └── @aws-amplify/graphql-transformer-core@3.5.1 deduped
│       │ ├─┬ @aws-amplify/graphql-maps-to-transformer@4.0.22
│       │ │ └── @aws-amplify/graphql-transformer-core@3.5.1 deduped
│       │ ├─┬ @aws-amplify/graphql-model-transformer@3.4.1
│       │ │ └── @aws-amplify/graphql-transformer-core@3.5.1 deduped
│       │ ├─┬ @aws-amplify/graphql-predictions-transformer@3.0.21
│       │ │ └── @aws-amplify/graphql-transformer-core@3.5.1 deduped
│       │ ├─┬ @aws-amplify/graphql-relational-transformer@3.1.13
│       │ │ └── @aws-amplify/graphql-transformer-core@3.5.1 deduped
│       │ ├─┬ @aws-amplify/graphql-searchable-transformer@3.1.2
│       │ │ └── @aws-amplify/graphql-transformer-core@3.5.1 deduped
│       │ ├─┬ @aws-amplify/graphql-sql-transformer@0.4.21
│       │ │ └── @aws-amplify/graphql-transformer-core@3.5.1 deduped
│       │ ├── @aws-amplify/graphql-transformer-core@3.5.1
│       │ ├─┬ @aws-amplify/graphql-transformer@2.4.2
│       │ │ └── @aws-amplify/graphql-transformer-core@3.5.1 deduped
│       │ └─┬ @aws-amplify/graphql-validate-transformer@1.1.6
│       │   └── @aws-amplify/graphql-transformer-core@3.5.1 deduped
│       ├─┬ @aws-amplify/graphql-auth-transformer@4.2.7
│       │ └── @aws-amplify/graphql-transformer-core@3.5.1 deduped
│       ├─┬ @aws-amplify/graphql-conversation-transformer@1.1.14
│       │ └── @aws-amplify/graphql-transformer-core@3.5.1 deduped
│       ├─┬ @aws-amplify/graphql-default-value-transformer@3.1.16
│       │ └── @aws-amplify/graphql-transformer-core@3.5.1 deduped
│       ├─┬ @aws-amplify/graphql-function-transformer@3.1.18
│       │ └── @aws-amplify/graphql-transformer-core@3.5.1 deduped
│       ├─┬ @aws-amplify/graphql-generation-transformer@1.2.6
│       │ └── @aws-amplify/graphql-transformer-core@3.5.1 deduped
│       ├─┬ @aws-amplify/graphql-http-transformer@3.0.21
│       │ └── @aws-amplify/graphql-transformer-core@3.5.1 deduped
│       ├─┬ @aws-amplify/graphql-index-transformer@3.1.1
│       │ └── @aws-amplify/graphql-transformer-core@3.5.1 deduped
│       ├─┬ @aws-amplify/graphql-maps-to-transformer@4.0.22
│       │ └── @aws-amplify/graphql-transformer-core@3.5.1 deduped
│       ├─┬ @aws-amplify/graphql-model-transformer@3.4.1
│       │ └── @aws-amplify/graphql-transformer-core@3.5.1 deduped
│       ├─┬ @aws-amplify/graphql-predictions-transformer@3.0.21
│       │ └── @aws-amplify/graphql-transformer-core@3.5.1 deduped
│       ├─┬ @aws-amplify/graphql-relational-transformer@3.1.13
│       │ └── @aws-amplify/graphql-transformer-core@3.5.1 deduped
│       ├─┬ @aws-amplify/graphql-searchable-transformer@3.1.2
│       │ └── @aws-amplify/graphql-transformer-core@3.5.1 deduped
│       ├─┬ @aws-amplify/graphql-sql-transformer@0.4.21
│       │ └── @aws-amplify/graphql-transformer-core@3.5.1 deduped
│       ├── @aws-amplify/graphql-transformer-core@3.5.1
│       ├─┬ @aws-amplify/graphql-transformer@2.4.2
│       │ └── @aws-amplify/graphql-transformer-core@3.5.1 deduped
│       └─┬ @aws-amplify/graphql-validate-transformer@1.1.6
│         └── @aws-amplify/graphql-transformer-core@3.5.1 deduped

node -e command returned:

@aws-amplify/data-construct => @aws-amplify/data-construct 1.17.3 C:\Users\denys\Personal\Work\trypennie-amplify\node_modules\@aws-amplify\data-construct\package.json
@aws-amplify/graphql-api-construct => @aws-amplify/graphql-api-construct 1.21.3 C:\Users\denys\Personal\Work\trypennie-amplify\node_modules\@aws-amplify\graphql-api-construct\package.json
@aws-amplify/graphql-transformer-core => @aws-amplify/graphql-transformer-core 3.5.1 C:\Users\denys\Personal\Work\trypennie-amplify\node_modules\@aws-amplify\graphql-transformer-core\package.json
@aws-amplify/data-construct/node_modules/@aws-amplify/graphql-transformer-core => @aws-amplify/graphql-transformer-core 3.5.1 C:\Users\denys\Personal\Work\trypennie-amplify\node_modules\@aws-amplify\data-construct\node_modules\@aws-amplify\graphql-transformer-core\package.json
@aws-amplify/graphql-api-construct/node_modules/@aws-amplify/graphql-transformer-core => @aws-amplify/graphql-transformer-core 3.5.1 C:\Users\denys\Personal\Work\trypennie-amplify\node_modules\@aws-amplify\graphql-api-construct\node_modules\@aws-amplify\graphql-transformer-core\package.json
STACK_MANAGER @aws-amplify/graphql-transformer-core/lib/transformer-context/stack-manager.js {
  path: 'C:\\Users\\denys\\Personal\\Work\\trypennie-amplify\\node_modules\\@aws-amplify\\graphql-transformer-core\\lib\\transformer-context\\stack-manager.js',
  patched: false,
  autoLimit: false
}
STACK_MANAGER @aws-amplify/data-construct/node_modules/@aws-amplify/graphql-transformer-core/lib/transformer-context/stack-manager.js {
  path: 'C:\\Users\\denys\\Personal\\Work\\trypennie-amplify\\node_modules\\@aws-amplify\\data-construct\\node_modules\\@aws-amplify\\graphql-transformer-core\\lib\\transformer-context\\stack-manager.js',
  patched: false,
  autoLimit: false
}
STACK_MANAGER @aws-amplify/graphql-api-construct/node_modules/@aws-amplify/graphql-transformer-core/lib/transformer-context/stack-manager.js {
  path: 'C:\\Users\\denys\\Personal\\Work\\trypennie-amplify\\node_modules\\@aws-amplify\\graphql-api-construct\\node_modules\\@aws-amplify\\graphql-transformer-core\\lib\\transformer-context\\stack-manager.js',
  patched: false,
  autoLimit: false
}

Regarding cli path, I don't have ampx installed globally, it's only project specific

@MarlonJD

Copy link
Copy Markdown
Author

Thanks, this output confirms the preview packages are not being applied yet.

The expected output should show:

  • @aws-amplify/data-construct => @marlonjd/data-construct 1.17.4-auto-shard-transformer-stacks.5
  • @aws-amplify/graphql-api-construct => @marlonjd/graphql-api-construct 1.21.4-auto-shard-transformer-stacks.5
  • STACK_MANAGER ... patched: true, autoLimit: true

Your output still shows the current published packages:

  • @aws-amplify/data-construct@1.17.3
  • @aws-amplify/graphql-api-construct@1.21.3
  • patched: false
  • autoLimit: false

So the sandbox is still running against the unpatched dependency tree.

Could you check that the overrides block is in the root package.json that owns the package-lock.json used by npm install? If this is an npm workspace/monorepo, the overrides need to be in the workspace root package.json, not only in a nested package.

Please run:

npm --version
npm pkg get overrides
npm explain @aws-amplify/data-construct
npm explain @aws-amplify/graphql-api-construct

Then reinstall from that same root and re-run the package check. Once the output shows the @marlonjd/* packages and patched: true, npx --no-install ampx sandbox should be testing the actual preview fix.

@RestingState

Copy link
Copy Markdown

Got

@aws-amplify/data-construct => @marlonjd/data-construct 1.17.4-auto-shard-transformer-stacks.5 C:\Users\denys\Personal\Work\trypennie-amplify\node_modules\@aws-amplify\data-construct\package.json
@aws-amplify/graphql-api-construct => @marlonjd/graphql-api-construct 1.21.4-auto-shard-transformer-stacks.5 C:\Users\denys\Personal\Work\trypennie-amplify\node_modules\@aws-amplify\graphql-api-construct\package.json
@aws-amplify/graphql-transformer-core => @marlonjd/graphql-transformer-core-stack-limits 3.5.1-stack-limits.5 C:\Users\denys\Personal\Work\trypennie-amplify\node_modules\@aws-amplify\graphql-transformer-core\package.json
@aws-amplify/data-construct/node_modules/@aws-amplify/graphql-transformer-core => @aws-amplify/graphql-transformer-core 3.5.1 C:\Users\denys\Personal\Work\trypennie-amplify\node_modules\@aws-amplify\data-construct\node_modules\@aws-amplify\graphql-transformer-core\package.json
@aws-amplify/graphql-api-construct/node_modules/@aws-amplify/graphql-transformer-core => @aws-amplify/graphql-transformer-core 3.5.1 C:\Users\denys\Personal\Work\trypennie-amplify\node_modules\@aws-amplify\graphql-api-construct\node_modules\@aws-amplify\graphql-transformer-core\package.json
STACK_MANAGER @aws-amplify/graphql-transformer-core/lib/transformer-context/stack-manager.js {
  path: 'C:\\Users\\denys\\Personal\\Work\\trypennie-amplify\\node_modules\\@aws-amplify\\graphql-transformer-core\\lib\\transformer-context\\stack-manager.js',
  patched: true,
  autoLimit: true
}
STACK_MANAGER @aws-amplify/data-construct/node_modules/@aws-amplify/graphql-transformer-core/lib/transformer-context/stack-manager.js {
  path: 'C:\\Users\\denys\\Personal\\Work\\trypennie-amplify\\node_modules\\@aws-amplify\\data-construct\\node_modules\\@aws-amplify\\graphql-transformer-core\\lib\\transformer-context\\stack-manager.js',
  patched: true,
  autoLimit: true
}
STACK_MANAGER @aws-amplify/graphql-api-construct/node_modules/@aws-amplify/graphql-transformer-core/lib/transformer-context/stack-manager.js {
  path: 'C:\\Users\\denys\\Personal\\Work\\trypennie-amplify\\node_modules\\@aws-amplify\\graphql-api-construct\\node_modules\\@aws-amplify\\graphql-transformer-core\\lib\\transformer-context\\stack-manager.js',
  patched: true,
  autoLimit: true
}
npm --version
11.12.1
PS C:\Users\denys\Personal\Work\trypennie-amplify> npm pkg get overrides
{
  "@aws-amplify/data-construct": "npm:@marlonjd/data-construct@1.17.4-auto-shard-transformer-stacks.5",
  "@aws-amplify/graphql-api-construct": "npm:@marlonjd/graphql-api-construct@1.21.4-auto-shard-transformer-stacks.5",
  "@aws-amplify/graphql-transformer": "npm:@marlonjd/graphql-transformer-stack-limits@2.4.2-stack-limits.2",
  "@aws-amplify/graphql-transformer-core": "npm:@marlonjd/graphql-transformer-core-stack-limits@3.5.1-stack-limits.5",
  "@aws-amplify/graphql-transformer-interfaces": "npm:@marlonjd/graphql-transformer-interfaces-stack-limits@4.3.0-stack-limits.2",
  "@aws-amplify/graphql-model-transformer": "npm:@marlonjd/graphql-model-transformer-stack-limits@3.4.1-stack-limits.2",
  "@aws-amplify/graphql-relational-transformer": "npm:@marlonjd/graphql-relational-transformer-stack-limits@3.1.13-stack-limits.4"
}

I use monorepo via turborepo. My main backend is located as packages/-main-backend and I run sandbox command via -w "-main-backend"

After all the changes, I run sandbox and got

3:15:35 PM [ERROR] [CloudFormationDeploymentError] The CloudFormation deployment has failed.
∟ Caused by: [ToolkitError] The stack named **amplify-<REDACTED>-sandbox-<REDACTED>** failed to deploy: UPDATE_ROLLBACK_COMPLETE:

Resource handler returned message: "Datasource with name FnSearchTemplatesLambdaDataSource already exists" (RequestToken: <REDACTED>, HandlerErrorCode: AlreadyExists),
Resource handler returned message: "Datasource with name FnSearchCancellationReasonsLambdaDataSource already exists" (RequestToken: <REDACTED>, HandlerErrorCode: AlreadyExists),
Resource handler returned message: "Datasource with name FnListCurrentTasksLambdaDataSource already exists" (RequestToken: <REDACTED>, HandlerErrorCode: AlreadyExists),
Resource handler returned message: "Datasource with name FnListTemplatePropertiesLambdaDataSource already exists" (RequestToken: <REDACTED>, HandlerErrorCode: AlreadyExists),
Resource handler returned message: "Datasource with name FnSearchConversionEventsLambdaDataSource already exists" (RequestToken: <REDACTED>, HandlerErrorCode: AlreadyExists),
Resource handler returned message: "Datasource with name FnSearchSegmentsLambdaDataSource already exists" (RequestToken: <REDACTED>, HandlerErrorCode: AlreadyExists),
Resource handler returned message: "Datasource with name FnGetPhoneNumberLambdaDataSource already exists" (RequestToken: <REDACTED>, HandlerErrorCode: AlreadyExists),
Resource handler returned message: "Datasource with name FnListQueuesLambdaDataSource already exists" (RequestToken: <REDACTED>, HandlerErrorCode: AlreadyExists),
Resource handler returned message: "Datasource with name FnGetTwilioAccessTokenLambdaDataSource already exists" (RequestToken: <REDACTED>, HandlerErrorCode: AlreadyExists),
Resource handler returned message: "Datasource with name FnSearchCampaignTagsLambdaDataSource already exists" (RequestToken: <REDACTED>, HandlerErrorCode: AlreadyExists),
Resource handler returned message: "Datasource with name FnSearchCampaignsLambdaDataSource already exists" (RequestToken: <REDACTED>, HandlerErrorCode: AlreadyExists),
Resource handler returned message: "Datasource with name FnSearchDispositionsLambdaDataSource already exists" (RequestToken: <REDACTED>, HandlerErrorCode: AlreadyExists),
Resource handler returned message: "Datasource with name FnSearchOwnedPhoneNumbersLambdaDataSource already exists" (RequestToken: <REDACTED>, HandlerErrorCode: AlreadyExists),
Resource handler returned message: "Datasource with name FnSearchTeamsLambdaDataSource already exists" (RequestToken: <REDACTED>, HandlerErrorCode: AlreadyExists),
Resource handler returned message: "Datasource with name FnSearchRecordingsLambdaDataSource already exists" (RequestToken: <REDACTED>, HandlerErrorCode: AlreadyExists),
Resource handler returned message: "Datasource with name FnRemoveQueueLambdaDataSource already exists" (RequestToken: <REDACTED>, HandlerErrorCode: AlreadyExists),
Resource handler returned message: "Datasource with name FnSearchNumberPoolLambdaDataSource already exists" (RequestToken: <REDACTED>, HandlerErrorCode: AlreadyExists),
Resource handler returned message: "Datasource with name FnSearchTaskPreferencesLambdaDataSource already exists" (RequestToken: <REDACTED>, HandlerErrorCode: AlreadyExists),
Resource handler returned message: "Datasource with name FnGetAuthUserLambdaDataSource already exists" (RequestToken: <REDACTED>, HandlerErrorCode: AlreadyExists),
Resource handler returned message: "Datasource with name FnSearchTaskTagsLambdaDataSource already exists" (RequestToken: <REDACTED>, HandlerErrorCode: AlreadyExists),
Resource handler returned message: "Datasource with name FnSearchUsersLambdaDataSource already exists" (RequestToken: <REDACTED>, HandlerErrorCode: AlreadyExists),
Resource handler returned message: "Datasource with name FnResolveContactIdentityLambdaDataSource already exists" (RequestToken: <REDACTED>, HandlerErrorCode: AlreadyExists),
Resource handler returned message: "Datasource with name FnGetQueuesStatisticLambdaDataSource already exists" (RequestToken: <REDACTED>, HandlerErrorCode: AlreadyExists),
Resource handler returned message: "Datasource with name FnSearchPurchasablePhoneNumbersLambdaDataSource already exists" (RequestToken: <REDACTED>, HandlerErrorCode: AlreadyExists),
Resource handler returned message: "Datasource with name FnListPublicApiKeysLambdaDataSource already exists" (RequestToken: <REDACTED>, HandlerErrorCode: AlreadyExists),
Resource handler returned message: "Datasource with name FnListAgentTemplateLambdaDataSource already exists" (RequestToken: <REDACTED>, HandlerErrorCode: AlreadyExists),
Resource handler returned message: "Datasource with name FnGetPersonalIntegrationsLambdaDataSource already exists" (RequestToken: <REDACTED>, HandlerErrorCode: AlreadyExists),
Resource handler returned message: "Datasource with name FnListAgentTaskTagsLambdaDataSource already exists" (RequestToken: <REDACTED>, HandlerErrorCode: AlreadyExists),
Resource handler returned message: "Datasource with name FnSearchSkillsLambdaDataSource already exists" (RequestToken: <REDACTED>, HandlerErrorCode: AlreadyExists),
Resource handler returned message: "Datasource with name FnListAgentDispositionsLambdaDataSource already exists" (RequestToken: <REDACTED>, HandlerErrorCode: AlreadyExists),
Resource handler returned message: "Datasource with name FnGetIntegrationsLambdaDataSource already exists" (RequestToken: <REDACTED>, HandlerErrorCode: AlreadyExists),
Resource handler returned message: "Datasource with name FnSearchContactsLambdaDataSource already exists" (RequestToken: <REDACTED>, HandlerErrorCode: AlreadyExists),
Resource handler returned message: "Datasource with name FnListRoutingRulesLambdaDataSource already exists" (RequestToken: <REDACTED>, HandlerErrorCode: AlreadyExists),
Resource handler returned message: "Datasource with name FnGetQueueLambdaDataSource already exists" (RequestToken: <REDACTED>, HandlerErrorCode: AlreadyExists),
Resource handler returned message: "Datasource with name FnSearchEventByTargetContactIdLambdaDataSource already exists" (RequestToken: <REDACTED>, HandlerErrorCode: AlreadyExists),
Resource handler returned message: "Datasource with name FnSearchEventsLambdaDataSource already exists" (RequestToken: <REDACTED>, HandlerErrorCode: AlreadyExists)

Embedded stack arn:aws:cloudformation:us-east-2:<REDACTED>:stack/<REDACTED>-apiFunctionDirectiveStack/<REDACTED> was not successfully created: The following resource(s) failed to create: [FnGetQueuesStatisticLambdaDataSource, FnListQueuesLambdaDataSource, FnSearchOwnedPhoneNumbersLambdaDataSource, FnSearchTeamsLambdaDataSource, FnSearchTaskTagsLambdaDataSource, FnSearchCancellationReasonsLambdaDataSource, FnSearchConversionEventsLambdaDataSource, FnListCurrentTasksLambdaDataSource, FnListAgentTemplateLambdaDataSource, FnGetPhoneNumberLambdaDataSource, FnSearchTaskPreferencesLambdaDataSource, FnResolveContactIdentityLambdaDataSource, FnSearchNumberPoolLambdaDataSource, FnSearchContactsLambdaDataSource, FnSearchTemplatesLambdaDataSource, FnSearchEventsLambdaDataSource, FnSearchPurchasablePhoneNumbersLambdaDataSource, FnSearchSkillsLambdaDataSource, FnSearchRecordingsLambdaDataSource, FnGetQueueLambdaDataSource, FnListPublicApiKeysLambdaDataSource, FnGetPersonalIntegrationsLambdaDataSource, FnListRoutingRulesLambdaDataSource, FnSearchCampaignsLambdaDataSource, FnGetIntegrationsLambdaDataSource, FnRemoveQueueLambdaDataSource, FnListAgentTaskTagsLambdaDataSource, FnSearchCampaignTagsLambdaDataSource, FnListTemplatePropertiesLambdaDataSource, FnGetAuthUserLambdaDataSource, FnSearchDispositionsLambdaDataSource, FnListAgentDispositionsLambdaDataSource, FnSearchUsersLambdaDataSource, FnGetTwilioAccessTokenLambdaDataSource, FnSearchSegmentsLambdaDataSource, FnSearchEventByTargetContactIdLambdaDataSource]. , Embedded stack arn:aws:cloudformation:us-east-2:<REDACTED>:stack/<REDACTED>-data7552DF31-<REDACTED>/<REDACTED> was not successfully updated. Currently in UPDATE_ROLLBACK_IN_PROGRESS with reason: The following resource(s) failed to create: [cadencemainbackendapiFunctionDirectiveStack2NestedStackFunctionDirectiveStack2NestedStackResourceCEF014FA]. The following resource(s) failed to update: [cadencemainbackendapiFunctionDirectiveStackNestedStackFunctionDirectiveStackNestedStackResourceEE2CBB83].

@RestingState

Copy link
Copy Markdown

The error persists even if I decrease the number of resources in function directive to below 500 limit

@MarlonJD

MarlonJD commented Jun 12, 2026

Copy link
Copy Markdown
Author

Thanks for the detailed repro. I found the root cause here: the previous stack sharding change could move AppSync API-scoped resources (AWS::AppSync::DataSource, AWS::AppSync::FunctionConfiguration, and AWS::AppSync::Resolver) from the original FunctionDirectiveStack into an overflow function stack during an update. For an existing sandbox, CloudFormation then tries to create AppSync resources whose physical names already exist, which causes the AlreadyExists failure.

I have a fix ready so those AppSync resources stay in the original function directive stack for existing deployments, while only the generated Lambda datasource IAM roles/policies can overflow into sharded stacks. The large @function regression test now verifies both sides: total resources still shard under the 500-resource limit, and the AppSync API-scoped resources remain together in a single template.

Update: I published a new preview package set with this fix:

{
  "overrides": {
    "@aws-amplify/data-construct": "npm:@marlonjd/data-construct@1.17.4-auto-shard-transformer-stacks.6",
    "@aws-amplify/graphql-api-construct": "npm:@marlonjd/graphql-api-construct@1.21.4-auto-shard-transformer-stacks.6",
    "@aws-amplify/graphql-transformer-core": "npm:@marlonjd/graphql-transformer-core-stack-limits@3.5.1-stack-limits.6"
  }
}

Please add this overrides block to the root package.json that owns the package-lock.json, then run npm install from that same root and retry with npx --no-install ampx sandbox.

I also verified the new override set in a clean temp npm project: @aws-amplify/backend resolved @aws-amplify/data-construct to @marlonjd/data-construct@1.17.4-auto-shard-transformer-stacks.6, resolved @aws-amplify/graphql-api-construct to @marlonjd/graphql-api-construct@1.21.4-auto-shard-transformer-stacks.6, and the bundled function/auth transformer files contain the update-stack-safe FunctionDirectiveStack fix.

@RestingState

Copy link
Copy Markdown

Hi @MarlonJD . After your update, it seems to be working.

I first run on stack with below limit and it already created a FunctionDirectiveStack2 where it put some of the operations. I had previously 475 resources in FunctionDirectiveStack. And after sandbox run I was decreased to 417 and other were migrated to FunctionDirectiveStack2. After I added additional queries/mutation, the count of resources on FunctionDirectiveStack remained the same (417) and the FunctionDirectiveStack2 got additional queries/mutations.

@RestingState

Copy link
Copy Markdown

What appears strange to me is that after adding even more queries/mutations I got 4 FunctionDirective stacks. Two of them have 51 resources each, one has 25 resources and the main big one has 399 resources.

Can you give a little insight into how the division works? How I can predict in what stacks the resources were allocated?

@MarlonJD

Copy link
Copy Markdown
Author

Thanks for testing and sharing the resource counts. I agree the distribution looks a bit surprising at first glance.

The current split is not trying to evenly balance the final CloudFormation resource counts across the FunctionDirective stacks. It is more conservative than that. For update safety, the AppSync API-scoped resources, such as DataSource, FunctionConfiguration, and Resolver, are kept in the original FunctionDirectiveStack. Moving those between nested stacks can be risky for existing deployments. The overflow stacks mainly receive the generated IAM roles and policies that are safer to move.

So a shape like 399 / 51 / 51 / 25 can happen: the large stack still contains the AppSync resources, while the smaller stacks contain the movable IAM resources. The exact split depends on generation order and the adaptive resource budget used during synth, so it is deterministic for a given schema/package version but not something users should rely on as a stable contract.

That said, I agree this is not ideal from a predictability/readability perspective. I am looking into a better follow-up approach so the placement is easier to reason about and handles larger @function-heavy schemas more cleanly.

@RestingState

Copy link
Copy Markdown

Thank you for response. Also, for the work that was done. Hope this solution will be checked by the amplify team and added to the main package

@RestingState

Copy link
Copy Markdown

Can you also provide the information on how ready are those packages for the usage in production? Is there something that you plan to add/edit before?

Right now we're pretty blocked on the development of the application, so we're discussing the idea of using your packages. Even though they're not merged yet.

Can you give info on it?

@RestingState

Copy link
Copy Markdown

@Simone319 Please, take a look at this PR. It worked for me and hope we can prepare it to be published to the main packages

@MarlonJD
MarlonJD force-pushed the fix/auto-shard-transformer-stacks branch from b458f47 to ffcd480 Compare June 15, 2026 09:47
@RestingState

Copy link
Copy Markdown

Are there any updates on the issue? Maybe there is an approximate timeline on when this feature is planned to be released?

@MarlonJD

Copy link
Copy Markdown
Author

Update after the last 399/51/51/25 validation snapshot:

  • Tightened update-safety behavior so existing stateful/root nested stacks keep their original parent across baseline -> expanded schema updates.
  • Pinned existing DynamoDB, Custom::AmplifyDynamoDBTable, and API-scoped AppSync resources instead of allowing generated stack grouping to re-parent them.
  • Added fail-closed placement classification for ambiguous API-scoped resources.
  • Enforced both CloudFormation limits: 500 resources per nested stack and 2500 resources per operation.
  • Centralized generated stack discovery/group helper logic in generated-stack-helpers.ts.
  • Added update-safety regression coverage for stateful stack parent stability, table/resource pinning, new overflow movement, non-function AppSync paths, and ambiguous AppSync placement.

Additional validation completed:

  • git diff --check
  • Focused construct tests: nested-stack-provider.test.ts, adaptive-sizer.test.ts, update-safety-placement.test.ts, resources.test.ts, construct-exports.test.ts
  • Transformer tests: stack-manager.test.ts, amplify-graphql-function-transformer.test.ts, get-scope-for-field.test.ts
  • Construct package tests: function-directive-stack-limits.test.ts, commands.test.ts, update-safety-change-set.test.ts
  • Builds for transformer interfaces/core/transformer/API construct plus corepack yarn extract-api
  • Local Verdaccio + clean consumer install/synth smoke
  • AWS baseline -> expanded schema change-set smoke in eu-central-1; cleanup check found no active stacks for AmplifyPreviewUpdateSafety-20260619-local

Preview update:

  • Published @marlonjd/graphql-api-construct@1.21.4-auto-shard-transformer-stacks.7
  • Updated dist-tag auto-shard-transformer-stacks to .7
  • Left latest unchanged

Not run:

  • Full cloud e2e was not triggered because local corepack yarn cloud-e2e requires scripts/.env e2e account configuration, and that file was not present.

@RestingState

Copy link
Copy Markdown

Hi Amplify team,

Could someone please take a look at this PR when possible? The issue it addresses has been open for quite some time and continues to affect users in production environments.

A review, feedback, or an update on next steps would be greatly appreciated. Thank you for your time and for maintaining Amplify.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants