serverless/serverless · error · ServerlessError

COGNITO_KMS_KEY_ID_NOT_SAME_FOR_SINGLE_USER_POOL

COGNITO_KMS_KEY_ID_NOT_SAME_FOR_SINGLE_USER_POOL

Error message

Only one KMS Key for can be configured per Cognito User Pool. Affected Cognito User Pool: "${currentPoolName}".

What it means

A single Cognito user pool can only be associated with one KMS key. If two triggers for the same pool specify different kmsKeyId values, checkKmsArn rejects the mismatch.

Source

Thrown at packages/serverless/lib/plugins/aws/package/compile/events/cognito-user-pool.js:392

    return null
  }

  checkKmsArn(kmsKeyId, poolKmsIdMap, currentPoolName) {
    // KMSKeyId is only used (and is required) with Custom Sender Sources
    if (!kmsKeyId) {
      throw new ServerlessError(
        `KMS Key must be set when using a Custom Sender Source Trigger (CustomSMSSender and/or CustomEmailSender). Affected Cognito User Pool: "${currentPoolName}".`,
        'COGNITO_KMS_KEY_NOT_SET',
      )
    }

    const previousKmsId = poolKmsIdMap.get(currentPoolName)
    if (
      previousKmsId !== undefined &&
      previousKmsId !== kmsKeyId &&
      JSON.stringify(previousKmsId) !== JSON.stringify(kmsKeyId)
    ) {
      throw new ServerlessError(
        `Only one KMS Key for can be configured per Cognito User Pool. Affected Cognito User Pool: "${currentPoolName}".`,
        'COGNITO_KMS_KEY_ID_NOT_SAME_FOR_SINGLE_USER_POOL',
      )
    }
    poolKmsIdMap.set(currentPoolName, kmsKeyId)
  }

  findUserPoolsAndFunctions() {
    const userPools = []
    const cognitoUserPoolTriggerFunctions = []

    // Iterate through all functions declared in `serverless.yml`
    this.serverless.service.getAllFunctions().forEach((functionName) => {
      const functionObj = this.serverless.service.getFunction(functionName)

      if (functionObj.events) {
        functionObj.events.forEach((event) => {
          if (event.cognitoUserPool) {

View on GitHub (pinned to b9d7ea51c8)

Solutions

  1. Use the same kmsKeyId for every trigger on a given pool.
  2. During key rotation, update all triggers for that pool together.
  3. Centralize the kmsKeyId in a custom variable so all triggers reference one source.

Example fix

# before
- cognitoUserPool: { pool: MyPool, trigger: CustomSMSSender,  kmsKeyId: arn:.../key/aaa }
- cognitoUserPool: { pool: MyPool, trigger: CustomEmailSender, kmsKeyId: arn:.../key/bbb }
# after
- cognitoUserPool: { pool: MyPool, trigger: CustomSMSSender,  kmsKeyId: arn:.../key/aaa }
- cognitoUserPool: { pool: MyPool, trigger: CustomEmailSender, kmsKeyId: arn:.../key/aaa }
Defensive patterns

Strategy: validation

Validate before calling

function inconsistentKmsPerPool(service) {
  const map = {};
  for (const e of allCognitoEvents(service)) {
    if (!e.kmsKeyId) continue;
    if (map[e.pool] && map[e.pool] !== e.kmsKeyId) return e.pool;
    map[e.pool] = e.kmsKeyId;
  }
  return null;
}

Prevention

When it happens

Trigger: poolKmsIdMap.get(currentPoolName) returns a previously seen key; if it differs from the new kmsKeyId (by value or JSON) the throw fires.

Common situations: Two custom-sender triggers on one pool pointing at different KMS keys; updating the key on only some triggers during a rotation; copy-paste from another pool's config.

Related errors


AI-assisted analysis of serverless/serverless@b9d7ea51c8 (2026-08-13). Data as JSON: /api/errors/da9d45350b2501c1. Report an issue: GitHub.