intermediate

Error handling

Отделяйте operational errors от programmer bugs, мапьте errors в responses, сохраняйте causes и избегайте unhandled rejections.

Разделяйте operational errors (ожидаемые сбои — validation, 404, таймаут upstream) и programmer errors (баги — null, нарушение инварианта). Operational мапятся в безопасный HTTP-ответ; programmer после лога могут завершить процесс, чтобы supervisor перезапустил испорченный инстанс.

					class AppError extends Error {
  constructor(message, { status = 500, code = 'INTERNAL', cause }) {
    super(message, { cause });
    this.status = status;
    this.code = code;
    this.isOperational = true;
  }
}

process.on('unhandledRejection', (reason) => {
  logger.error({ reason }, 'unhandled rejection');
  shutdown(1);
});
				

Async-ошибки всегда в `next(err)` или аналог фреймворка. Сохраняйте цепочку `cause`; из клиентского JSON убирайте внутренние детали.

На интервью: operational vs programmer; форма централизованного error middleware; опасность «проглоченных» rejection.

Типовые ошибки: пустой `catch {}`; 500 со stack trace клиенту; разные формы ошибок по маршрутам.

Чеклист:

  • Структурированные ошибки приложения.
  • Один mapper ответов для API.
  • Мониторинг unhandledRejection/uncaughtException.
  • Stack только на сервере.