Skip to content

Gen1 to Gen2 Migration - Authorization Trigger Lambdas create circular dependency if accessing data tables #3286

Description

@benjeater

Environment information

System:
  OS: macOS 26.5.2
  CPU: (10) arm64 Apple M4
  Memory: 212.81 MB / 16.00 GB
  Shell: /bin/zsh
Binaries:
  Node: 24.15.0 - /Users/benjeater/.nvm/versions/node/v24.15.0/bin/node
  Yarn: undefined - undefined
  npm: 11.17.0 - /Users/benjeater/.nvm/versions/node/v24.15.0/bin/npm
  pnpm: undefined - undefined
NPM Packages:
  @aws-amplify/auth-construct: 1.11.2
  @aws-amplify/backend: 1.23.0
  @aws-amplify/backend-ai: Not Found
  @aws-amplify/backend-auth: 1.9.4
  @aws-amplify/backend-cli: 1.8.3
  @aws-amplify/backend-data: 1.7.0
  @aws-amplify/backend-deployer: 2.1.7
  @aws-amplify/backend-function: 1.18.1
  @aws-amplify/backend-output-schemas: 1.8.0
  @aws-amplify/backend-output-storage: 1.3.5
  @aws-amplify/backend-secret: 1.4.2
  @aws-amplify/backend-storage: 1.5.0
  @aws-amplify/cli-core: 2.2.5
  @aws-amplify/client-config: 1.10.2
  @aws-amplify/data-construct: 1.17.4
  @aws-amplify/data-schema: 1.26.0
  @aws-amplify/deployed-backend-client: 1.8.2
  @aws-amplify/form-generator: 1.2.7
  @aws-amplify/model-generator: 1.2.3
  @aws-amplify/platform-core: 1.11.1
  @aws-amplify/plugin-types: 1.12.1
  @aws-amplify/sandbox: 2.2.1
  @aws-amplify/schema-generator: 1.4.1
  @aws-cdk/toolkit-lib: 1.19.0
  aws-amplify: 6.18.0
  aws-cdk-lib: 2.261.0
  typescript: 6.0.3
CDK CLI Version: 2.1130.0 (build a7a40e0)
normal verbosity, no debugging
AWS environment variables:
  AWS_PROFILE = aerios-ben-profile
  AWS_EC2_METADATA_DISABLED = true
No CDK environment variables

Describe the bug

Problem

When migrating a Gen 1 application to Gen 2 which uses Auth Triggers AND at least one of the Auth Trigger Lambdas has access to a Data table, it is not possible to deploy the Gen 2 environment because of circular dependencies that cannot be rectified using the resourceGroupName key on the defineFunction function as documented in https://docs.amplify.aws/vue/build-a-backend/troubleshooting/circular-dependency/#circular-dependency-error-between-nested-stacks.

Example

You have a Gen 1 application with auth,api, and function configured to provide a Cognito user pool, a User table in DynamoDB, and a Lambda function called postConfirmationLambda.

This auth configuration includes a trigger on Post Confirmation to use the postConfirmationLambda function.

The postConfirmationLambda function creates a User record in DynamoDB when called by the auth post-confirmation trigger logic (the functionality mentioned in this example file but in Gen 1).

After migrating to Gen 2, a circular dependency is created which cannot be resolved with the resourceGroupName key on the defineFunction function.

  • The defineAuth function has a populated triggers.postConfirmation key which points to the postConfirmationLambda defineFunction function
// amplify/auth/resource.ts

import { postConfirmationLambda } from '../function/postConfirmationLambda/resource';

export const auth = defineAuth({
 ...,
  triggers: {
    postConfirmation: postConfirmationLambda
  },
});
  • The defineFunction function uses the applyEscapeHatches function to grant itself access to the User table
// amplify/function/postConfirmationLambda/resource.ts

export function applyEscapeHatches(backend: Backend) {
  backend.postConfirmationLambda.addEnvironment(
    'API_APINAME_USERTABLE_ARN',
    backend.data.resources.tables['User'].tableArn,
  );
  backend.postConfirmationLambda.addEnvironment(
    'API_APINAME_USERTABLE_NAME',
    backend.data.resources.tables['User'].tableName,
  );

  backend.data.resources.tables['User'].grant(
    backend.postConfirmationLambda.resources.lambda,
    'dynamodb:Put*',
    ...
  )
}
  • The User table defined in the GraphQL schema (i.e. not migrated to the a.schema functionality) utilises the @auth directive, which requires the auth resource
# amplify/data/resource.ts

"""
Represents a single user in the system
"""
type User @model(queries: { get: "getUser", list: null }) @auth(rules: [{ allow: groups, groupsField: "id" }]) {
  id: ID!
  email: String! @index(name: "byEmail") 
  ...
}

The auth requires the function, which requires the data, which requires the auth; therefore we have a circular dependency.

Investigation Steps

  • The example article seems to indicate that this is not a problem, but seems to be acheived by using the a.schema definition.

Reproduction steps

  1. Create an Amplify Gen 1 application where the authorization setup includes a lambda trigger that creates a user profile record in the post-confirmation lambda (like in https://docs.amplify.aws/react/build-a-backend/functions/examples/create-user-profile-record/)
  2. Migrate to Gen 2
  3. Attempt to run npx ampx sandbox --once to test the migration
  4. Error occurs, there is a circular dependency

Metadata

Metadata

Assignees

No one assigned

    Labels

    pending-community-responseIssue is pending a response from the author or communityquestionQuestion or confusion about some aspect of the product

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions