AUTH_KEY_DUPLICATED: el error silencioso que mata tu cuenta de Telegram
Por qué tu cuenta se desconecta sola, qué hace Telegram cuando detecta dos conexiones con la misma clave y cómo evitarlo en producción.
Si llevas más de un mes operando un userbot en producción, vas a ver este error: AUTH_KEY_DUPLICATED. No tiene mensaje explicativo, no aparece en la docs pública de Telegram con claridad, y silenciosamente desconecta tu cuenta. Es la causa #1 de pérdida de sesiones MTProto en SaaS de Telegram.
Esta guía explica qué es exactamente, por qué pasa, qué hace Telegram cuando lo detecta y cómo evitarlo.
Qué dice Telegram, técnicamente
Telegram impone una regla estricta a nivel de protocolo: una auth_key solo puede tener una conexión activa a la vez. Cuando un segundo cliente intenta usar la misma auth_key:
- El servidor de Telegram detecta dos clientes con el mismo identificador
- Devuelve
AUTH_KEY_DUPLICATEDa la conexión más antigua - Mata las dos conexiones
- Si pasa repetidamente, Telegram empieza a marcar la sesión como sospechosa
El problema: GramJS y la mayoría de los clientes MTProto no levantan una excepción "fatal" — devuelven un disconnect silencioso. Tu app cree que la cuenta sigue válida, pero está desconectada.
Por qué pasa en producción
Las tres causas más comunes:
Causa 1: Dos workers cargan la misma sesión a la vez
Tienes una cola con tareas y N workers consumiendo. Una tarea para la cuenta A llega al worker 1. Mientras está procesando, llega otra tarea para la cuenta A al worker 2. Worker 2 carga la sesión, abre cliente MTProto. Boom: AUTH_KEY_DUPLICATED.
Frecuencia: si tienes 5 cuentas y 1 worker, casi nunca. Con 50 cuentas y 4 workers procesando una cola compartida, decenas de veces al día.
Causa 2: Sesión cargada en frontend Y en backend
Algunos productos cargan la sesión en el navegador del usuario (para "preview en vivo") además del backend que envía mensajes. Cada vez que el usuario abre la app, abre conexión. Si el backend también abre, choque.
Solución obvia: sesiones MTProto nunca se cargan en el frontend. Solo en backend.
Causa 3: Reconexión sin esperar el disconnect previo
Tu worker se cae con un error, se reinicia automáticamente, abre cliente con la misma sesión inmediatamente. Telegram aún tiene la conexión vieja medio-viva (TCP timeout normal: 60-120s). Resultado: dos conexiones simultáneas brevemente, AUTH_KEY_DUPLICATED.
Solución: esperar al menos 30s entre disconnect y reconnect del mismo auth_key.
Lo que pasa después: la cascada
Una vez Telegram emite AUTH_KEY_DUPLICATED en tu cuenta:
- Primera vez: las dos conexiones se cortan, todo intento de reconnect inmediato falla
- Segunda vez en pocos minutos: la sesión empieza a fallar en
getMe()con error sutil - Tres-cuatro veces: Telegram invalida la sesión.
StringSessiondeja de funcionar - Cinco veces en una hora: la cuenta puede entrar en bandera "sospechosa" y recibir FloodWait largos
Hemos visto cuentas perder validez en menos de 10 minutos cuando el bug del lock no estaba resuelto y la cola tenía decenas de tareas para la misma cuenta.
La solución: lock distribuido por cuenta
El patrón correcto, probado en producción:
import { redis } from "@/lib/redis";
const TTL_LOCK_SEGUNDOS = 30;
const ESPERA_MAX_MS = 5000;
export async function conLockConexionMTProto<T>(
accountId: string,
fn: () => Promise<T>
): Promise<T> {
const key = `mtproto:lock:${accountId}`;
const inicio = Date.now();
while (Date.now() - inicio < ESPERA_MAX_MS) {
const ok = await redis.set(key, process.pid, "EX", TTL_LOCK_SEGUNDOS, "NX");
if (ok) {
try {
return await fn();
} finally {
await redis.del(key);
}
}
await new Promise((r) => setTimeout(r, 100));
}
throw new Error(`Lock no disponible para cuenta ${accountId}`);
}Cada cliente MTProto se abre dentro de conLockConexionMTProto(accountId, ...). Si dos workers compiten por la misma cuenta, uno espera hasta que el otro termina (o falla después de 5s).
El TTL de 30s es crítico: si un proceso se cae sin liberar el lock, Redis lo expira automáticamente. Sin TTL, una caída deja un lock huérfano para siempre.
Patrones más sutiles
Lock + best-effort fallback
A veces el lock no está disponible por más de 5s (alta concurrencia) y prefieres seguir adelante. Cuidado: ese fallback es el que genera AUTH_KEY_DUPLICATED. Solo úsalo si:
- Es para operaciones read-only que no abren conexión nueva (consultar caché de mensajes ya enviados)
- Tienes alarma activa: si el fallback dispara > N veces/hora, escalar
Singleton del cliente
Otra técnica: mantener una sola instancia de cliente MTProto por accountId en memoria del worker. Las tareas la reusan en vez de abrir/cerrar.
const clientes = new Map<string, TelegramClient>();
async function obtenerCliente(accountId: string) {
if (!clientes.has(accountId)) {
const cliente = await crearCliente(accountId);
clientes.set(accountId, cliente);
}
return clientes.get(accountId)!;
}Combinado con lock distribuido, este patrón elimina el 99% de los AUTH_KEY_DUPLICATED.
Disconnect graceful con esperas
Al cerrar, no llames disconnect() y abras inmediatamente otra conexión:
await client.disconnect();
await new Promise((r) => setTimeout(r, 1000));
// ahora puedes reconnect si necesarioEl segundo (1000ms) le da a Telegram tiempo de procesar el cierre del TCP.
Cómo recuperar una sesión que ya cayó
Si una sesión ya recibió AUTH_KEY_DUPLICATED múltiples veces y ahora falla:
- Intenta un
client.connect()limpio (a veces vuelve) - Si falla con
AUTH_KEY_UNREGISTERED, la sesión está muerta: el usuario tiene que reautenticarse con SMS - Si vuelve a conectar, marca la cuenta como "warmup" durante 24h: bájale la cuota de envíos al 50% para no agravar
No hay magia: una sesión muerta es muerta. La prevención es lo único que escala.
Observability mínimo
Tu app debe alertarte de esto antes de perder cuentas:
- Métrica: número de
AUTH_KEY_DUPLICATEDpor hora - Alerta: si > 3 en 10min, página al on-call
- Dashboard: lista de cuentas que han disparado el error en las últimas 24h
- Log estructurado: cada disparo con
accountId, timestamp yworker_pid
Esto te permite encontrar el bug en horas, no en semanas.
La pregunta clave para evaluar herramientas
Si vas a contratar un SaaS de Telegram, pregúntales:
"¿Cómo manejan AUTH_KEY_DUPLICATED y cuántos ven por mes?"
Las respuestas posibles:
- "¿Qué es eso?" → corre. No tienen producción real.
- "Lo manejamos con retry" → mal. Retry sin lock empeora el problema.
- "Tenemos lock distribuido con Redis y singleton de cliente, vemos < 5 al mes en 10K cuentas" → buena señal.
Vega Punk y AUTH_KEY_DUPLICATED
En Vega Punk usamos conLockConexionMTProto con Redis + TTL 30s en todos los puntos donde abrimos cliente: workers, API routes que necesitan MTProto, scripts de mantenimiento. Antes del fix, veíamos ~50 por día. Después: < 2 por semana, y todos por casos de borde resueltos en el siguiente release.
La diferencia entre producto funcional y producto profesional es manejar exactamente este tipo de error con detalle.
Conclusión
AUTH_KEY_DUPLICATED no es un bug raro: es estructural si tu arquitectura no lo previene. Lock distribuido + singleton de cliente + observability son la tríada que lo elimina.
Si tu SaaS de Telegram tiene clientes quejándose de "mi cuenta se desconectó sola", probablemente sea esto. Resolverlo cuesta 2-3 días de un dev senior. No resolverlo cuesta clientes.