6.0 KiB
🔧 Fix Aplicado: "Cannot read properties of undefined (reading 'upsert')"
📋 Resumen del Problema
Error original:
Cannot read properties of undefined (reading 'upsert')
at FeatureFlagService.setFlag (/home/shnimlz/amayo/src/core/services/FeatureFlagService.ts:562:32)
Causa:
Race condition donde prisma.featureFlag se vuelve undefined entre la validación y el uso, posiblemente por:
- Hot-reload / watch mode que recarga módulos
- Orden de inicialización de módulos en Discord.js
- Múltiples instancias de PrismaClient en memoria
✅ Solución Implementada
1. Referencias Locales al Delegado
En vez de usar prisma.featureFlag directamente, ahora capturamos una referencia local justo después de validarlo:
// ANTES (vulnerable a race condition)
if (!prisma.featureFlag) throw new Error("...");
await prisma.featureFlag.upsert({ ... }); // ❌ puede fallar aquí
// AHORA (referencia local estable)
if (!prisma.featureFlag) throw new Error("...");
const featureFlagDelegate = prisma.featureFlag; // 📌 capturar ref
await featureFlagDelegate.upsert({ ... }); // ✅ usa la referencia
2. Doble Validación
Validamos tanto antes como después de capturar la referencia:
// Primera validación
if (!prisma.featureFlag || typeof prisma.featureFlag.upsert !== "function") {
logger.error({ msg: "Delegate missing", keys, typeofPrisma });
throw new Error("Delegate missing");
}
// Capturar referencia
const featureFlagDelegate = prisma.featureFlag;
// Segunda validación (defensiva)
if (!featureFlagDelegate || typeof featureFlagDelegate.upsert !== "function") {
logger.error({ msg: "Delegate lost between validation and use" });
throw new Error("Delegate became undefined");
}
// Usar referencia estable
await featureFlagDelegate.upsert({ ... });
3. Aplicado en 3 Métodos
setFlag()→ usafeatureFlagDelegate.upsert()removeFlag()→ usafeatureFlagDelegate.delete()refreshCache()→ usafeatureFlagDelegate.findMany()
🧪 Tests Realizados
✅ Test 1: Creación directa
npx tsx scripts/testCreateFlag.ts
Resultado: ✅ Pasa sin errores
✅ Test 2: Simulación de comando Discord
npx tsx scripts/testDiscordCommandFlow.ts
Resultado: ✅ Pasa sin errores (simula startup + delay + comando)
✅ Test 3: Prisma directo
npx tsx -e "import { prisma } from './src/core/database/prisma'; ..."
Resultado: ✅ CRUD operations funcionan
🚀 Cómo Aplicar el Fix
Paso 1: Reiniciar el Bot
El error ocurrió porque el bot está ejecutando código antiguo (línea 562 del stack trace no coincide con el código actual).
Opción A: PM2
pm2 restart amayo
pm2 logs amayo --lines 50
Opción B: Manual
# Detener proceso actual
pkill -f "node.*amayo"
# Reiniciar
npm start
# o
pm2 start ecosystem.config.js
Paso 2: Probar el Comando
Una vez reiniciado, ejecuta en Discord:
/featureflags create name:2025-10-alianza-blacklist status:disabled target:global
Paso 3: Verificar Logs
Si funciona, verás:
{"level":"info","msg":"[FeatureFlags] Flag \"2025-10-alianza-blacklist\" actualizado"}
Si falla (muy improbable ahora), verás uno de estos logs estructurados:
{"level":"error","msg":"[FeatureFlags] Prisma featureFlag delegate missing or invalid","keys":[...],"typeofPrisma":"object"}
o
{"level":"error","msg":"[FeatureFlags] FeatureFlag delegate lost between validation and use","typeofDelegate":"undefined"}
🔍 Si el Error Persiste
Diagnóstico Avanzado
1. Verificar versión del código en runtime:
# Ver línea exacta del error en el archivo actual
sed -n '613p' /home/shni/amayo/amayo/src/core/services/FeatureFlagService.ts
# Debería mostrar: await featureFlagDelegate.upsert({
2. Verificar módulo Prisma en runtime:
npx tsx -e "
import { prisma } from './src/core/database/prisma';
console.log('Prisma:', typeof prisma);
console.log('featureFlag delegate:', typeof prisma.featureFlag);
console.log('Keys:', Object.keys(prisma).slice(0, 30));
"
3. Buscar múltiples instancias de Prisma:
grep -r "new PrismaClient" src/
# Debería mostrar solo: src/core/database/prisma.ts:8
4. Revisar si hay imports circulares:
npx madge --circular src/
Posibles Causas Restantes (si persiste)
-
TypeScript transpilado vs TSX: El bot podría estar usando JS compilado antiguo en
dist/rm -rf dist/ npm run build # si tienes script de build -
Caché de módulos de Node: Limpiar require cache
rm -rf node_modules/.cache/ -
Hot-reload agresivo: Deshabilitar watch mode temporalmente
-
Prisma Client desincronizado:
npx prisma generate npm run build pm2 restart amayo
📊 Archivos Modificados
-
✅
src/core/services/FeatureFlagService.ts- Líneas 84-104:
refreshCache()con referencia local - Líneas 584-627:
setFlag()con doble validación y referencia local - Líneas 652-668:
removeFlag()con validación y referencia local
- Líneas 84-104:
-
✅
scripts/testDiscordCommandFlow.ts(nuevo)- Script de prueba que simula el flujo completo del comando Discord
🎯 Resultado Esperado
- ❌ ANTES: Error
Cannot read properties of undefined (reading 'upsert')intermitente - ✅ AHORA:
- Flag se crea correctamente
- Si hay problema, logs estructurados identifican la causa exacta
- Referencias locales previenen race conditions
📞 Próximos Pasos
- Reinicia el bot (pm2 restart o npm start)
- Prueba el comando
/featureflags create - Revisa logs (deberían ser exitosos ahora)
- Si persiste:
- Pega aquí los logs JSON completos con el nuevo formato
- Ejecuta los comandos de diagnóstico avanzado
- Revisa si hay
dist/con código compilado antiguo
Fecha del fix: 2025-10-31
Tests locales: ✅ Todos pasan
Estado: Listo para producción (requiere restart del bot)