خطاها و کدها — 400 تا 504 و راهحل هر کدام
جدول کامل خطاهای API از 400 تا 504 با کد هر خطا، شکل JSON خطا و بلوک یوتاپن، کار درست در هر حالت، و نگاشت خطاها به exception های SDK رسمی OpenAI.
بهروزرسانی: ۱ مهر ۱۴۰۵
همهٔ خطاها با همان شکل خطای OpenAI برمیگردند تا SDKها آنها را به exception درست تبدیل کنند. فرق ما یک بلوک اضافه به نام uttapen است که در بعضی خطاها اطلاعات عملی میدهد (مثلاً مبلغ لازم و لینک شارژ).
شکل خطا
{
"error": {
"message": "موجودی کافی نیست. برای اجرای این درخواست دستکم حدود 54٬139 تومان شارژ لازم است (موجودی قابلاستفاده: 97٬518 تومان).",
"type": "insufficient_balance",
"code": "insufficient_balance",
"param": null,
"uttapen": {
"balance_toman": "97517.828964",
"available_toman": "97517.828964",
"required_toman": "54138.610606",
"topup_url": "https://uttapen.ir/dashboard/wallet"
}
}
}
codeوtypeهمیشه یکیاند؛ رویcodeشرط بگذار.messageفارسی و برای نمایش به کاربر نهایی مناسب است. پیامهایی که از سمت سازندهٔ مدل میآیند انگلیسیاند.uttapenفقط وقتی هست که چیزی برای گفتن داریم؛ روی وجودش شرط بگذار.- هدر
X-Uttapen-Request-Idروی خطاها هم هست. برای گزارش مشکل همین را بفرست.
جدول خطاها
| status | code | کِی | چه کنی |
|---|---|---|---|
400 | invalid_request | JSON نامعتبر، model نبود، فیلد عددی رشته یا اعشاری بود، /v1/embeddings با مدلی که embedding نیست یا chat/completions با مدل embedding، plugins یا models شکل غلط دارد | بدنه را درست کن؛ تکرار بیفایده است |
400 | invalid_request (از سمت مدل) | پارامتری که مدل نمیپذیرد (مثلاً temperature روی مدل استدلالی، تصویر به مدل متنی) یا درخواست بزرگتر از ظرفیت لحظهای سازندهٔ مدل | پارامتر را حذف کن یا max_tokens را کم کن |
401 | invalid_api_key | کلید نیامده، غلط، لغوشده یا منقضی | کلید تازه از داشبورد؛ تکرار نکن |
402 | insufficient_balance | موجودی قابلاستفاده کمتر از مبلغ رزرو این درخواست، یا موجودی منفی | شارژ کن (uttapen.topup_url) یا max_tokens را کم کن؛ درخواست به مدل نرفته |
403 | account_suspended | حساب توسط ادمین معلق شده | با پشتیبانی تماس بگیر |
403 | model_not_allowed | مدل بیرون از allowed_models این کلید | مدل دیگر یا تنظیم کلید |
404 | model_not_found | شناسهٔ مدل وجود ندارد، مخفی یا حذف شده؛ شناسه بدون پیشوند سازنده | شناسه را از /v1/models بردار |
404 | not_found | مسیر وجود ندارد یا /v1/responses که هنوز فعال نیست | /v1/chat/completions |
413 | request_too_large | بدنه بزرگتر از ۲۰ مگابایت | تصویر را کوچک کن یا متن PDF را بفرست |
429 | rate_limit_exceeded | بیش از rate_limit_rpm کلید در یک دقیقه | Retry-After را صبر کن |
429 | key_monthly_limit_reached | سقف ماهانهٔ کلید پر شده (uttapen.monthly_limit_toman، spent_toman) | سقف را بالا ببر یا کلید دیگر |
429 | too_many_concurrent_streams | بیش از ۱۰ استریم یا درخواست embeddings باز برای این کاربر | یکی تمام شود؛ Retry-After: 5 |
429 | free_quota_exceeded | سهم روزانهٔ مدلهای رایگان تمام شد (uttapen.alternative_model) | مدل پولی یا فردا |
429 | free_capacity_exhausted | ظرفیت مشترک مدل رایگان در سمت سازنده تمام شده | مدل پولی؛ Retry-After |
429 | upstream_rate_limited | سازندهٔ مدل آن را موقتاً محدود کرده | چند ثانیه صبر و تکرار، یا مدل همرده |
502 | upstream_error | خطای ۵xx سمت مدل، پاسخ ناقص، یا خطای وسط استریم | تکرار با فاصلهٔ فزاینده؛ رزرو آزاد یا با مصرف واقعی تسویه شده |
503 | upstream_unavailable | اتصال به سازندهٔ مدل برقرار نشد یا هیچ ظرفیتی در دسترس نیست | Retry-After: 30؛ تکرار |
503 | server_busy | فضای موقت پاسخهای بزرگ embeddings — کل آن یا سهم حساب تو — موقتاً پر است؛ پیش از هر هزینهای رد میشود | Retry-After: 30؛ یا دستهٔ کوچکتر و درخواستهای همزمان کمتر |
503 | pricing_unavailable | قیمتگذاری موقتاً تنظیم نشده (فقط در راهاندازی اولیه) | چند دقیقه بعد |
504 | upstream_timeout | ۱۲۰ ثانیه بدون هیچ بایتی از سمت مدل | تکرار؛ برای مدلهای کند stream: true |
4xx دیگر | همان کد سازندهٔ مدل | خطای سازندهٔ مدل با همان کد وضعیت | پیام را بخوان |
خطاهای 5xx و 429 امن برای تکرارند: هیچکدام بدون این که پاسخ بگیری هزینهای برایت نمیگذارند. 400 و 401 و 403 و 404 را تکرار نکن؛ نتیجه همان است.
هزینه در خطا
قاعده ساده است: اگر پاسخ نگرفتی، پول ندادهای. رزرو در خطاهای قبل از ارسال اصلاً انجام نمیشود و در خطاهای سمت مدل همان لحظه آزاد میشود. تنها استثنا خطای وسط استریم است که بخشی از پاسخ رسیده؛ آنجا فقط مصرف واقعی تا لحظهٔ قطع تسویه میشود (استریم).
نگاشت به SDKها
Python (openai) — هر status به یک کلاس:
| status | exception |
|---|---|
400 | openai.BadRequestError |
401 | openai.AuthenticationError |
402 | openai.APIStatusError (کلاس اختصاصی ندارد؛ status_code == 402) |
403 | openai.PermissionDeniedError |
404 | openai.NotFoundError |
413 | openai.APIStatusError |
429 | openai.RateLimitError |
502، 503، 504 | openai.InternalServerError |
| قطع شبکه / پایان مهلت (timeout) | openai.APIConnectionError، openai.APITimeoutError |
import openai
try:
resp = client.chat.completions.create(model="openai/gpt-5-mini", messages=msgs)
except openai.AuthenticationError:
raise SystemExit("کلید uttapen نامعتبر است")
except openai.RateLimitError as e:
wait = int(e.response.headers.get("retry-after", "5"))
time.sleep(wait)
except openai.APIStatusError as e:
if e.status_code == 402:
info = e.body["error"]["uttapen"]
print("موجودی کافی نیست؛ شارژ لازم:", info["required_toman"], "تومان —", info["topup_url"])
else:
print(e.status_code, e.code, e.message)
e.code همان error.code ماست، e.body کل بدنهٔ JSON و e.response.headers هدرها (شامل x-uttapen-request-id). SDK بهصورت پیشفرض 429 و 5xx را دو بار با فاصلهٔ فزاینده تکرار میکند؛ با max_retries تنظیمش کن.
Node.js (openai) — همان نامها: AuthenticationError، RateLimitError، NotFoundError، BadRequestError، PermissionDeniedError، InternalServerError؛ برای 402 کلاس عمومی APIError با err.status === 402. err.code و err.error.uttapen در دسترساند.
try {
await client.chat.completions.create({ model: "openai/gpt-5-mini", messages });
} catch (err) {
if (err instanceof OpenAI.APIError) {
console.error(err.status, err.code, err.error?.uttapen);
} else throw err;
}
PHP (openai-php/client) — همهٔ خطاهای HTTP OpenAI\Exceptions\ErrorException هستند با getStatusCode()، getErrorCode() و getMessage(). بلوک uttapen را این کلاینت نگه نمیدارد؛ برای 402 مبلغ را از پیام بخوان یا با Guzzle خام بدنه را بگیر.
Go (openai-go) — var apierr *openai.Error; errors.As(err, &apierr) سپس apierr.StatusCode، apierr.Code، apierr.Message و apierr.RawJSON() برای بلوک uttapen.
توصیه برای کد تولیدی
- روی
codeشرط بگذار نه روی متنmessage؛ متن ممکن است تغییر کند. - برای
429و5xxتکرار با فاصلهٔ نمایی و کمی تصادف (jitter)، حداکثر سه تلاش.Retry-Afterرا اگر بود، رعایت کن. 402را به کاربر یا ادمین خودت نشان بده و تکرار نکن؛ تا شارژ نشود همان میماند.X-Uttapen-Request-Idرا در لاگ خودت کنار خطا بنویس. وقتی از پشتیبانی میپرسی، با همین شناسه در چند ثانیه پیدایش میکنیم.- قبل از deploy،
GET /v1/uttapen/meرا بزن تا کلید، مدل مجاز و موجودی را یکجا ببینی.
با شماره موبایل ثبتنام کن، کیف پول را از ۱۰۰٬۰۰۰ تومان شارژ کن و کلید بساز. مدلهای رایگان بدون شارژ هم کار میکنند — تا ۵۰ درخواست در روز. ساخت کلید API ←