HACER CUMPLIR el manejo de errores centralizado y seguro. Capturar TODOS los errores en un solo lugar. Registrar todo. Devolver respuestas seguras y consistentes. Prevenir fugas de traza de pila, rechazos de promesas no manejados, formatos de error inconsistentes y fallos silenciosos. Activadores: "handle errors", "build an error handler", "fix the crash", "return an error response".
Install with Codex or Claude Copy this prompt, paste it into Codex, Claude, or another assistant, and let it review the skill page and install it for you.
A direct command skips the review prompt. Inspect the source before running it.
HACER CUMPLIR el manejo de errores centralizado y seguro. Capturar TODOS los errores en un solo lugar. Registrar todo. Devolver respuestas seguras y consistentes. Prevenir fugas de traza de pila, rechazos de promesas no manejados, formatos de error inconsistentes y fallos silenciosos. Activadores: "handle errors", "build an error handler", "fix the crash", "return an error response".
// Errores predefinidos, úsalos, no construyas AppError en línea
export
const
Errors
notFound
(resource: string) =>
new
AppError
`${resource} no encontrado`
404
code
'NOT_FOUND'
badRequest
(message: string) =>
new
AppError
400
code
'BAD_REQUEST'
unauthorized
(message = 'No autorizado') =>
new
AppError
401
code
'UNAUTHORIZED'
forbidden
(message = 'Prohibido') =>
new
AppError
403
code
'FORBIDDEN'
conflict
(message: string) =>
new
AppError
409
code
'CONFLICT'
tooManyRequests
(message = 'Límite de tasa excedido') =>
new
AppError
429
code
'RATE_LIMITED'
Paso 2: Lanzar Errores desde la Lógica de Negocio, NO desde los Manejadores de Ruta
// ✅ La lógica de negocio lanza, los manejadores están limpiosasyncfunctiongetUserById(id: string) {
const user = await db.user.findUnique({ where: { id } });
if (!user) throwErrors.notFound('Usuario');
return user;
}
// Manejador de ruta, limpio, sin formato de error en línea
app.get('/api/users/:id', async (req, res, next) => {
try {
const user = awaitgetUserById(req.params.id);
res.json({ data: user });
} catch (err) {
next(err); // Reenviar al manejador global
}
});
Paso 3: Construir Manejador Global de Errores (UN manejador, usado por TODAS las rutas)
Paso 4: Estandarizar Formato de Respuesta de Error (RFC 9457 Problem Details)
SIEMPRE usar esta estructura:
// Mínimo, siempre incluir mensaje y estado{"error":{"message":"Usuario no encontrado","status":404}}// Completo, para APIs públicas (RFC 9457){"type":"https://api.example.com/errors/not-found","title":"Recurso No Encontrado","status":404,"detail":"El usuario con ID 'abc123' no existe.","instance":"/api/users/abc123"}
Paso 5: Mapear Errores de Base de Datos a Mensajes Amigables
NUNCA devolver errores crudos de base de datos:
try {
await db.user.create({ data });
} catch (err) {
if (err instanceofPrisma.PrismaClientKnownRequestError) {
if (err.code === 'P2002') throwErrors.conflict('Ya existe un usuario con este correo');
if (err.code === 'P2025') throwErrors.notFound('Registro relacionado');
}
throw err; // Relanzar errores BD inesperados al manejador global
}
Patrones Específicos por Stack
Express 5 (estable actual: captura errores asíncronos de forma nativa)
app.use((err: Error, req: Request, res: Response, next: NextFunction) => {
// Manejador global de errores, DEBE ser el último
});