Обработка ошибок в Go: паттерны и best practices

Мы просто и по делу рассказываем про ИИ-инструменты для работы: сравнения, пошаговые гайды, бесплатные альтернативы и реальные сценарии применения. Помогаем выбрать между ChatGPT, Gemini, Claude, локальными моделями и десятками узкоспециализированных сервисов — от дизайна и HR до аналитики и SEO. Меньше хайпа, больше практики и экономии времени каждый день.

Goобработка ошибокerrors.Is

В Go ошибки — это часть обычного потока выполнения, а не исключение “где-то в фоне”. Поэтому качественная обработка ошибок напрямую влияет на стабильность, читаемость и поддержку кода.

Почему в Go ошибки возвращаются явно

Go придерживается принципа простоты: функция возвращает error, а вызывающий код сам решает, что делать дальше. Это делает поведение программы предсказуемым и упрощает отладку.

Типичный паттерн:

result, err := doWork()
if err != nil {
    return fmt.Errorf("doWork failed: %w", err)
}

1. Всегда добавляйте контекст к ошибке

Одна из лучших практик — не возвращать ошибку “как есть”, а оборачивать её через %w.

return fmt.Errorf("failed to read config: %w", err)

Так вы получаете:

  • понятную цепочку ошибок
  • больше информации в логах
  • возможность проверять первопричину через errors.Is и errors.As

2. Используйте errors.Is вместо сравнения строк

Сравнивать err.Error() — плохая практика. Текст ошибки может измениться.

if errors.Is(err, os.ErrNotExist) {
    // файл не найден
}

Это надёжнее и соответствует idiomatic Go ✅

3. Для кастомных типов — errors.As

Если нужно извлечь конкретный тип ошибки:

var pathErr *os.PathError
if errors.As(err, &pathErr) {
    log.Println(pathErr.Path)
}

errors.As полезен, когда важно поведение или поля ошибки, а не только факт её наличия.

4. Sentinel errors — осторожно

Иногда удобно объявить ошибку как переменную:

var ErrUserNotFound = errors.New("user not found")

Это подходит для известных бизнес-сценариев. Но не стоит плодить десятки sentinel errors без необходимости — API становится хрупким.

5. Не логируйте одну и ту же ошибку много раз

Частая проблема — ошибка логируется на каждом уровне вызова. В итоге в логах шум.

Хороший подход:

  • либо оборачивать ошибку и логировать её один раз на верхнем уровне
  • либо логировать только там, где есть реальное решение или реакция

6. Не игнорируйте ошибки

Конструкция _ = someFunc() допустима редко. Особенно опасно игнорировать:

  • Close()
  • запись в файл или сеть
  • json.Marshal / Unmarshal
  • работу с БД

Даже “маловероятная” ошибка в проде рано или поздно проявится 💥

7. Ошибки должны быть полезными для пользователя и разработчика

Для внешнего клиента:

  • без утечки внутренних деталей
  • с понятным сообщением

Для логов и мониторинга:

  • максимум технического контекста
  • request ID, параметры, источник сбоя

8. Panic — не для обычных ошибок

panic в Go используют для действительно аварийных ситуаций:

  • нарушение инвариантов
  • критическая ошибка инициализации
  • баг в программе

Для бизнес-логики, сетевых ошибок и проблем ввода-вывода нужен обычный error, а не panic 🚨

Итог

Хорошая обработка ошибок в Go строится на 4 принципах:

  • явный возврат error
  • оборачивание с контекстом через %w
  • проверка через errors.Is и errors.As
  • минимум шума в логах

Именно это делает Go-код надёжным, поддерживаемым и удобным в эксплуатации 🔍🛠️

Подборку каналов про IT — с практикой, архитектурой, Go и разработкой — стоит сохранить отдельно в закладки 📚

🗣 Подборки каналов
🧠 Каталог ботов и приложений
🗺 Навигация

Читайте так же