400 Bad Request почти ничего не дает для диагностики — настоящий ответ был в JSON, который она отбросила.Реальный случай: 400 Bad Request ничего вам не говорит
Клиент сообщил ровно одну строку:400 обычно означает либо проверку безопасности контента, либо проблему с параметром. Скорее всего, проверку безопасности контента.Это предположение, а не вывод. Потому что для того же самого вызова фактическое тело ответа могло быть любым из следующих трех вариантов — и каждый из них требует совершенно разного действия:
Что есть и чего нет в backend log
Сначала важно правильно понять ментальную модель: backend log — это журнал тарификации, а не журнал ошибок.7 полей, которые вы должны сохранить
Это все, что нужно, чтобы диагностировать один неудачный вызов. Если не хватает хотя бы одного из них, диагностика снова превращается в догадки:status_code >= 400 — тела ошибок и так короткие.Правильные шаблоны захвата ошибок
По сути, есть только один принцип: перехватывайте на двух уровнях и ничего не теряйте ни на одном из них.- Сбои на транспортном уровне: сброс соединения, сбой TLS-рукопожатия, тайм-аут, сбой DNS. Ответа HTTP вообще нет — у вас есть только текст исключения.
- Ошибки на уровне HTTP: сервер вернул 4xx / 5xx. Ответ есть, и вы должны прочитать его тело.
Python / requests
Python / OpenAI SDK
Официальный SDK уже прикрепляет к объекту исключения все три части. Большинство людей вместо этого простоprint собственное однострочное сообщение:
Node.js
С SDK:fetch чаще всего ошибка возникает именно здесь:
Воспроизведение с помощью cURL
Когда вы просите кого-то воспроизвести проблему, эта команда требует меньше всего усилий — она одним запуском показывает код состояния, заголовки, тело и время выполнения:-iвыводит заголовки ответа, где и находитсяx-request-id;-sSскрывает индикатор выполнения, но сохраняет вывод ошибок;-wдобавляет код состояния и общее время, что удобно для сравнения с вашими настройками тайм-аута.
Обертки и внутренние шлюзы
Хороший пример
Эта ошибка пришла из узла ComfyUI клиента:400 Bad Request — и при этом оно полное, поэтому направление определяется за секунды:
400 Bad Request); другой длинный и уродливый и прямо указывает на коренную причину (errno 10054). Для диагностики сырая, уродливая и полная ошибка всегда лучше дружелюбной, аккуратной, переписанной версии.Где найти сырой вывод в распространенных инструментах
Три правила для внутреннего шлюза
Не переписывайте, а только пропускайте дальше
error.message. После переписывания больше негде восстановить исходный текст.Храните сообщение для пользователя отдельно от исходного
userMessage (дружелюбный текст для конечных пользователей), devMessage (ваша классификация для разработчиков) и rawResponse (тело ответа без изменений). Первые два поля можно свободно полировать; третье храните дословно.Никогда не выдавайте неизвестную ошибку
status, x-request-id и первые 2000 символов тела. «Неклассифицированная ошибка», которая сохраняет исходный текст, поддается диагностике; чистая «неизвестная ошибка» — нет.Антипаттерны, делающие диагностику невозможной
except Exception as e: print("request failed")— объект исключения исчез, и вы даже не знаете, какой слой отказал;- Записывать код состояния, но не тело — именно тот случай, что вверху этой страницы;
- Вызывать
raise_for_status(), не прочитав сначалаresp.text, — сообщение все еще находится в памяти, просто никогда не извлекается; if (!resp.ok) throw new Error(resp.statusText)вfetch— тело отбрасывается вместе с объектом ответа;- Оставлять только чистый 200 после успешной повторной попытки — регистрируйте каждую попытку отдельно, иначе вы никогда не увидите, сколько раз отказал транспорт, и можете принять собственные повторы за поведение шлюза;
- Логировать только в stdout или ежедневно ротировать с перезаписью — к тому времени, когда клиент сообщит о проблеме, исходная запись обычно уже уходит из видимой области;
- Сообщать о проблеме по фото экрана с телефона — лучше вставьте текст; скриншоты регулярно обрезают половину строки ошибки.
Когда обращаться в поддержку
Сначала пройдите описанные выше шаги захвата и интерпретации. Если выполняется хотя бы одно из следующих условий, передайте материалы в поддержку:- У вас есть полное тело ответа, и
error.messageуказывает на upstream (upstream_error, необработанный upstream 5xx или явная ошибка канала); - Те же параметры запроса работают на другой модели или в другое время, и стабильно сбой происходит только у одной конкретной модели;
- Ошибка — это
500+write_response_body_failedили похожий сбой доставки downstream, и она воспроизводится стабильно (за это не тарифицируются; см. Обрывы соединения); - Вы подозреваете, что тарификация не совпадает с вашими фактическими вызовами — только
request_idпозволяет точно сверить данные.
Шаблон обращения в поддержку (копируйте и вставляйте)
Поддержка WeCom

@apiyi001 или по email [email protected].Связанная документация
Руководство по API
Обрывы соединения
ECONNRESET, errno 10054 и SSL EOFAPI запроса логов
request_id и сверять тарификациюЧтение начисленных сумм
Настройка таймаута
Основы Image API
400 invalid_image_file