Los Atributos de AWS Cognito User Pool No Pueden Ser Cambiados: Un Análisis Profundo.

Consola de AWS Amplify con un despliegue fallido y el error CFNUpdateNotSupportedError al cambiar atributos del grupo de usuarios de Cognito

RESUMEN

Los atributos del pool de usuarios no pueden ser cambiados después de que se ha creado un pool de usuarios porque los atributos de Cognito User Pool son inmutables después de la creación. Fusionar ramas con diferentes configuraciones de autenticación rompe los despliegues. Solución Rápida: Elimina la pila de CloudFormation (aws cloudformation delete-stack --stack-name YOUR-STACK) y redespliega. ⚠️ Esto elimina todos los usuarios. Prevenlo: Define todos los atributos de usuario y grupos antes de tu primer despliegue en producción. Usa aplicaciones Amplify separadas por entorno en lugar de despliegues basados en ramas.

Introducción

Cómo una fusión simple rompió mi despliegue y qué aprendí sobre los atributos inmutables de Cognito

Si alguna vez has visto este error durante un despliegue de AWS Amplify, no estás solo:

[CFNUpdateNotSupportedError] User pool attributes cannot be changed after a user pool has been created.

Resource handler returned message: "Invalid AttributeDataType input, consider using the provided AttributeDataType enum."

Este error detuvo mi despliegue en producción en seco. Aquí está lo que sucedió, por qué sucede, y cómo tanto repararlo como prevenirlo.

El Escenario

Estaba trabajando en un proyecto AWS Amplify Gen 2 con despliegues basados en ramas. Mi configuración:

  • rama main → Entorno de Producción
  • rama pdf-transcript → Desarrollo de características

La rama de características se desplegó exitosamente. La fusioné a main. Entonces... falla de despliegue.

Causa Raíz: Esquema Inmutable de Cognito

Los Pools de Usuarios de Amazon Cognito tienen una limitación fundamental: ciertos atributos no pueden ser modificados después de que se crea el Pool de Usuarios. Esto incluye:

  • Requisitos de atributos estándar (requerido vs opcional)
  • Definiciones de atributos personalizados
  • Tipos de datos de atributos
  • Algunas configuraciones de mutabilidad de atributos

Cuando CloudFormation intenta actualizar un Pool de Usuarios con cambios de atributos incompatibles, falla y se revierte.

Qué Cambió en Mi Caso

Mi rama main tenía una configuración de autenticación simple:

// Original main branch
export const auth = defineAuth({
  loginWith: {
    email: true,
  },
});

La rama de características añadió atributos de usuario y grupos:

// After merge from feature branch
export const auth = defineAuth({
  loginWith: {
    email: true,
  },
  userAttributes: {
    email: {
      mutable: true,
      required: true,
    },
    preferredUsername: {
      mutable: true,
      required: false,
    },
  },
  groups: ["ADMINS", "EDITORS"],
});

El Pool de Usuarios de la rama main fue creado sin preferredUsername. CloudFormation no pudo añadirlo al pool existente.

El Error Explicado

Veamos desglosar el mensaje de error:

UPDATE_ROLLBACK_COMPLETE: Resource handler returned message:
"Invalid AttributeDataType input, consider using the provided
AttributeDataType enum."

Este mensaje críptico en realidad significa: "Estás intentando cambiar los atributos del Pool de Usuarios de una manera que Cognito no permite."

La sugerencia de resolución en los registros es en realidad útil:

Resolution: To change these attributes, remove `defineAuth` from your
backend, deploy, then add it back. Note that removing `defineAuth` and
deploying will delete any users stored in your UserPool.

Soluciones

Solución 1: Eliminar y Recrear (Sin Usuarios para Preservar)

Si no tienes usuarios en el entorno afectado, la solución más rápida es eliminar la pila de CloudFormation y redesplegarse:

# Delete the stack
aws cloudformation delete-stack \
  --stack-name amplify-YOUR-APP-ID-BRANCH-NAME-HASH \
  --region us-east-1

# Wait for deletion
aws cloudformation wait stack-delete-complete \
  --stack-name amplify-YOUR-APP-ID-BRANCH-NAME-HASH \
  --region us-east-1

# Trigger redeploy from Amplify Console or:
aws amplify start-job \
  --app-id YOUR-APP-ID \
  --branch-name main \
  --job-type RELEASE \
  --region us-east-1

Solución 2: Despliegue de Dos Fases (Sugerencia de Amplify)

Si necesitas un enfoque basado en código:

  • Elimina defineAuth de amplify/backend.ts
  • Despliega (esto elimina el Pool de Usuarios)
  • Vuelve a añadir defineAuth con la nueva configuración
  • Despliega nuevamente
// Phase 1: backend.ts without auth
import { defineBackend } from "@aws-amplify/backend";
import { data } from "./data/resource";
import { storage } from "./storage/resource";

defineBackend({
  // auth,  // Commented out
  data,
  storage,
});

Solución 3: Migración de Usuarios (Producción con Usuarios)

Si tienes usuarios que necesitas preservar:

  • Exporta usuarios usando la funcionalidad de exportación de Cognito o una Lambda personalizada
  • Crea un nuevo Pool de Usuarios con los atributos correctos
  • Importa usuarios al nuevo pool
  • Usa el Disparador de Lambda de Migración de Usuarios para autenticación sin problemas durante la transición
// User migration trigger example
export const handler = async (event) => {
  if (event.triggerSource === "UserMigration_Authentication") {
    // Verify user in old pool
    // Return user attributes for new pool
    event.response.userAttributes = {
      email: event.userName,
      email_verified: "true",
    };
    event.response.finalUserStatus = "CONFIRMED";
    event.response.messageAction = "SUPPRESS";
  }
  return event;
};

Prevención: Mejores Prácticas

1. Planifica Tu Esquema de Antemano

Antes de tu primer despliegue en producción, define TODOS los atributos que puedas necesitar:

export const auth = defineAuth({
  loginWith: {
    email: true,
  },
  userAttributes: {
    // Include everything you might need in the future
    email: { mutable: true, required: true },
    preferredUsername: { mutable: true, required: false },
    givenName: { mutable: true, required: false },
    familyName: { mutable: true, required: false },
    phoneNumber: { mutable: true, required: false },
    // Custom attributes if needed
  },
  // Include all potential groups
  groups: ["ADMINS", "EDITORS", "VIEWERS", "BETA_USERS"],
});

2. Usa Aplicaciones Amplify Separadas para Entornos

En lugar de despliegues basados en ramas en la misma aplicación:

pdf-resurrector-dev    → Development (feature branches)
pdf-resurrector-staging → Staging (pre-production testing)
pdf-resurrector-prod   → Production (main branch only)

Esto aísla completamente los Pools de Usuarios entre entornos.

3. Prueba Cambios de Autenticación en Sandbox Primero

Siempre ejecuta localmente antes de hacer push:

npx ampx sandbox

Esto crea un entorno aislado donde puedes detectar conflictos de esquema temprano.

4. Usa Revisiones de Infraestructura como Código

Añade configuración de autenticación a tu lista de verificación de revisión de PR:

  • Cambios de esquema de autenticación revisados
  • Los nuevos atributos son solo aditivos
  • Probados en entorno sandbox
  • Plan de migración documentado (si hay cambios importantes)

5. Documenta Tu Esquema de Autenticación

Mantén un documento vivo de tu configuración de autenticación:

## User Pool Schema (Locked)

| Attribute         | Type   | Required | Mutable | Added |
| ----------------- | ------ | -------- | ------- | ----- |
| email             | String | Yes      | Yes     | v1.0  |
| preferredUsername | String | No       | Yes     | v1.0  |
| givenName         | String | No       | Yes     | v1.0  |

⚠️ DO NOT remove or modify existing attributes
✅ New attributes can be added (optional only)

Lo que Cognito SÍ Te Permite Cambiar

No todo es inmutable. PUEDES modificar:

  • Disparadores de Lambda (pre/post autenticación, etc.)
  • Políticas de contraseña
  • Configuraciones de MFA
  • Plantillas de correo electrónico/SMS
  • Configuraciones de cliente de aplicación
  • Configuración de dominio
  • Añadir nuevos atributos estándar opcionales (en algunos casos)

Conclusión

El diseño de atributos inmutables de Cognito es un compromiso por la integridad y seguridad de datos. Una vez que existen usuarios con ciertos atributos, cambiar el esquema podría corromper sus datos.

Los puntos clave a recordar:

  • Planifica tu esquema de autenticación antes del lanzamiento en producción
  • Usa entornos separados con Pools de Usuarios aislados
  • Prueba cambios de autenticación en sandbox primero
  • Ten una estrategia de migración para cambios en producción

Este error me costó una hora de depuración y una reversión de despliegue. Con suerte, este artículo te ahorra el mismo dolor de cabeza.


Recursos

  • Actualización asincrónica de elementos relacionados con AWS DataStore en una aplicación web Next.js.

    Al trabajar con AWS DataStore tienes que lidiar con operaciones async/await. Actualizar una lista de elementos cuando el orden de ejecución de las operaciones asincrónicas no es obligatorio es viable hacerlo con Promise.all() y map. Actualizar elementos relacionados, donde el resultado de la promesa del elemento anterior es necesario como entrada para el siguiente elemento, se puede lograr con la declaración for await...of.

  • No se puede resolver amplify_outputs.json

    Para corregir el error de compilación "no se puede resolver amplify_outputs.json", añade npx ampx pipeline-deploy --branch $AWS_BRANCH --app-id $AWS_APP_ID a la configuración de compilación y adjunta la política AdministratorAccess-Amplify

  • ¿Cómo usar un dominio personalizado registrado con AWS Route 53 en una aplicación web Next.js implementada en Vercel?

    Actualiza los servidores de nombres del dominio de AWS Route 53 o, los tipos de registros A y CNAME con los valores proporcionados por Vercel bajo ProjectName / Settings / Domains después de que agregaste un dominio al proyecto. Mostrará la información necesaria para configurar midominio.com y redirigir a www.midominio.com o viceversa. Después de que intentaste agregar el dominio a tu proyecto sin éxito, esa información también se enviará a tu correo electrónico explicando qué hacer. Vercel te permite configurar registros A (recomendado) y CNAME.