رفتن به محتوا
مدیریت خطا

مدیریت خطا

درخواستی که ناموفق باشد یک کد وضعیت HTTP و یک بدنه JSON با نوع خطا و پیام برمی‌گرداند. این صفحه هر وضعیت را فهرست می‌کند، بدنه خطای هر فرمت API را نشان می‌دهد و می‌گوید ارسال دوباره کدام خطاها ارزش دارد.

SDKها یک شیء خطا می‌اندازند که کد وضعیت و فیلدهای بدنه را دارد. این درخواست مدلی را نام می‌برد که وجود ندارد:

import openai
from openai import OpenAI

client = OpenAI(
    api_key="YOUR_API_KEY",
    base_url="https://api.shannon-ai.com/v1",
)

try:
    client.chat.completions.create(
        model="no-such-model",
        messages=[{"role": "user", "content": "Hello"}],
    )
except openai.APIStatusError as error:
    print(error.status_code)                           # 400
    print(error.type)                                  # invalid_request_error
    print(error.body["message"])                       # unknown model: no-such-model
    print(error.response.headers.get("x-request-id"))  # the id of this request

وضعیت 400 و این بدنه را برمی‌گرداند:

400 JSON
{
  "error": {
    "type": "invalid_request_error",
    "message": "unknown model: no-such-model"
  }
}

بدنه خطا

دو بدنه وجود دارد. /v1/messages با فرمت Anthropic پاسخ می‌دهد؛ هر endpoint دیگر با فرمت OpenAI. در هر دو، جزئیات در error.type و error.message است، پس یک خواننده برای همه endpointها کافی است.

401 فرمت OpenAI
{
  "error": {
    "type": "authentication_error",
    "message": "Invalid API key",
    "code": "invalid_api_key",
    "param": null
  }
}
401 فرمت Anthropic
{
  "type": "error",
  "error": {
    "type": "authentication_error",
    "message": "Invalid API key"
  }
}
فیلد نوع توضیحات
error.type string نوع خطا. «انواع خطا» را در ادامه ببینید.
error.message string یک جمله برای انسان. متن‌های جدول‌های زیر تا بخش‌های متغیرشان، که به شکل <id>، <n> یا … نشان داده شده، ثابت‌اند.
error.code string | null در برخی خطاهای فرمت OpenAI وجود دارد: invalid_api_key با 401، request_too_large با 413، context_length_exceeded وقتی گفتگو خیلی بلند است، در غیر این صورت null یا وجود ندارد. ابتدا بر اساس وضعیت و error.type تصمیم بگیرید و code را اطلاعات اضافی در نظر بگیرید.
error.param null روی همان خطاهایی وجود دارد که code دارند. همیشه null.
type string فقط در فرمت Anthropic. همیشه error.

انواع خطا

نوع وضعیت‌ها توضیحات
invalid_request_error 400, 413, 415, 422 خود درخواست نادرست است: یک فیلد، بدنه، شناسه مدل یا ورودی‌ای که مدل نمی‌پذیرد. پیش از ارسال دوباره درخواست را تغییر دهید.
authentication_error 401 کلید API وجود ندارد، ناشناخته یا ابطال‌شده است.
not_found_error 404 مسیر وجود ندارد.
rate_limit_error 429 موجودی درخواست را پوشش نمی‌دهد، محافظت در برابر هجوم درخواست آن را متوقف کرده، یا مدل مشغول است. پیام می‌گوید کدام.
api_error 500, 502, 503, 504 درخواست درست بود و شکست از سمت ماست. دوباره بفرستید.
server_error 500 درخواست درست بود و شکست از سمت ماست. دوباره بفرستید.

کدهای وضعیت

وضعیت نوع پیام زمان
400 invalid_request_error Failed to parse the request body as JSON: … بدنه JSON معتبر نیست.
400 invalid_request_error unknown model: <id> model شناسه منتشرشده نیست. روی /v1/responses وقتی model وجود نداشته باشد هم همین‌طور.
400 invalid_request_error No user message provided سطوح Shannon: درخواست متن کاربر ندارد.
400 invalid_request_error <id> does not accept image input یک تصویر به مدل open-weight میزبانی‌شده‌ای فرستاده شد که ورودی تصویر ندارد.
400 invalid_request_error audio and video input are not supported by any hosted model یک بخش صوتی یا تصویری به مدل open-weight میزبانی‌شده فرستاده شد.
400 invalid_request_error <id> does not accept response_format خروجی ساختاریافته از مدل open-weight میزبانی‌شده‌ای خواسته شد که آن را ندارد.
400 invalid_request_error <id> does not accept response_format json_schema; use json_object یک JSON schema به مدل open-weight میزبانی‌شده‌ای فرستاده شد که فقط json_object می‌پذیرد.
400 invalid_request_error unknown reasoning effort '<value>'; expected off, low, medium or high میزان تلاش استدلال یکی از مقادیر فهرست‌شده نیست. مدل‌های open-weight میزبانی‌شده.
400 invalid_request_error count_tokens is available for the hosted open models; unknown model: <id> شمارش توکن برای مدلی خارج از مدل‌های open-weight میزبانی‌شده درخواست شد.
401 authentication_error Missing authentication هیچ کلید API ارسال نشد.
401 authentication_error Invalid API key کلید ناشناخته است، با کلید جدیدتری جایگزین شده یا ابطال شده است.
404 not_found_error Not Found مسیر وجود ندارد، برای مثال /v1/embeddings.
405 api_error Method Not Allowed مسیر وجود دارد اما نه با این متد HTTP.
413 invalid_request_error Failed to buffer the request body: … بدنه درخواست از 32 MiB بزرگ‌تر است.
415 invalid_request_error Expected request with `Content-Type: application/json` هدر Content-Type وجود ندارد یا application/json نیست.
422 invalid_request_error Failed to deserialize the JSON body into the target type: … یک فیلد الزامی، مانند messages، وجود ندارد، یا نوع JSON یک فیلد نادرست است.
429 rate_limit_error Quota exceeded. Upgrade your plan at shannon-ai.com/plan حد خروجی درخواست از باقی‌مانده موجودی شما بزرگ‌تر است.
429 rate_limit_error Too many requests. Retry in <n>s. محافظت در برابر هجوم درخواست (flood protection): بیش از 120 درخواست در یک دقیقه روی حساب شما. <n> تعداد ثانیه‌های باقی‌مانده تا پایان دقیقه است.
429 rate_limit_error Shannon Coder call quota reached. Upgrade your plan at shannon-ai.com/plan shannon-coder-1 روی /v1/chat/completions و /v1/messages: فراخوانی‌های Shannon Coder پلن شما برای بازه 4 ساعته فعلی مصرف شده است.
429 rate_limit_error Shannon routes are temporarily busy. Please retry. مدل در این لحظه مشغول است.
500 server_error The model backend failed to answer. Please retry. مدل پاسخی تولید نکرد.
500 server_error An internal error occurred. Please retry. یک شکست داخلی هنگام آماده‌سازی درخواست.
502 api_error The model backend failed to answer. Please retry. مدل پاسخی تولید نکرد. خانواده Shannon 3 و مدل‌های open-weight میزبانی‌شده.
503 api_error Could not verify your quota right now. Please retry. موجودی شما در این لحظه خوانده نشد.
503 api_error token counting is temporarily unavailable for this model شمارش توکن در این لحظه برای این مدل در دسترس نیست.
504 api_error upstream timed out یک مدل open-weight میزبانی‌شده بیش از محدودیت زمانیِ درخواستی که stream نمی‌شود طول کشید.

بررسی‌ها به این ترتیب انجام می‌شوند: کلید API، بدنه درخواست، شناسه مدل، محافظت در برابر هجوم درخواست، موجودی. بنابراین درخواستی با کلید نادرست و بدنه نادرست 401 برمی‌گرداند. درخواستی که با وضعیت 4xx رد شود محاسبه نمی‌شود.

موجودی و محافظت در برابر هجوم درخواست

هر درخواست به‌طور برابر سرویس می‌گیرد: سطح‌بندی نرخ و سهمیه جداگانه API وجود ندارد. با این حال دو چیز می‌توانند با 429 پاسخ دهند، هر دو با نوع rate_limit_error. پیام آن‌ها را از هم تفکیک می‌کند.

موجودی

موجودی شما سهمیه روزانه پلن امروز است که ساعت 00:00 UTC بازنشانی می‌شود و پس از آن اعتبار خریداری‌شده. چت و API از یک موجودی مشترک برداشت می‌کنند.

هر درخواست ابتدا حد خروجی خود را کنار می‌گذارد: max_tokens یا max_output_tokens روی /v1/responses، و اگر هیچ‌کدام را نفرستید 4,096. وقتی پاسخ کامل شود، مقدار کنار گذاشته‌شده با آنچه درخواست مصرف کرده جایگزین می‌شود. اگر این مقدار در موجودی باقی‌مانده جا نشود، درخواست پیش از شروع مدل Quota exceeded برمی‌گرداند.

درخواست‌هایی که هم‌زمان اجرا می‌شوند هرکدام مقدار خود را کنار می‌گذارند. بنابراین درخواست‌های موازی زیاد با max_tokens بالا می‌توانند موجودی را برای لحظه‌ای تمام کنند، حتی اگر هر پاسخ کوتاه باشد. max_tokens پایین‌تر مقدار کمتری کنار می‌گذارد.

محافظت در برابر هجوم درخواست

محافظت در برابر هجوم درخواست (flood protection) 120 درخواست در دقیقه برای هر حساب مجاز می‌داند. حساب را می‌شمارد، نه کلید را، و /v1/chat/completions، /v1/responses و /v1/messages را با هم در نظر می‌گیرد. دقیقه با اولین درخواست شما شروع می‌شود.

درخواست شماره 121 در آن دقیقه Too many requests. Retry in <n>s. برمی‌گرداند و هزینه‌ای ندارد. درخواست‌های ردشده هم شمرده می‌شوند، پس کلاینتی که بدون انتظار دوباره می‌فرستد تا پایان دقیقه رد می‌شود. به اندازه <n> ثانیه‌ای که در پیام آمده صبر کنید.

درخواست‌هایی که موازی فرستاده می‌شوند به‌خاطر موازی بودن رد نمی‌شوند. در صف منتظر می‌مانند و به نوبت پاسخ داده می‌شوند.

GET /v1/models و endpointهای شمارش توکن شمرده نمی‌شوند.

بیشتر درباره محدودیت‌ها و موجودی، و اینکه موجودی و مصرف خود را کجا ببینید: محدودیت‌ها و موجودی کلیدها و مصرف

چه چیزی را دوباره امتحان کنیم

فقط وقتی درخواست را دوباره بفرستید که همان درخواست بتواند موفق شود. SDKهای OpenAI و Anthropic پاسخ‌های 429 و 5xx را خودشان دو بار دوباره امتحان می‌کنند؛ برای تغییر آن max_retries (در JavaScript maxRetries) را تنظیم کنید.

خطا دوباره بفرستم؟ چگونه
400, 404, 405, 413, 415, 422 نه. ابتدا درخواست را اصلاح کنید. پیام، فیلد، مدل یا ورودی نادرست را نام می‌برد.
401 نه. از یک کلید معتبر استفاده کنید. کلید را در صفحه «کلیدها و مصرف» بسازید یا عوض کنید.
429 Too many requests بله، پس از انتظار. به اندازه ثانیه‌های ذکرشده در پیام صبر کنید، سپس همان درخواست را بفرستید.
429 Quota exceeded نه به همین شکل. max_tokens را کم کنید، منتظر بازنشانی روزانه در ساعت 00:00 UTC بمانید، یا اعتبار اضافه کنید.
429 Shannon Coder call quota reached بله، در بازه بعدی. بازه‌ها هر 4 ساعت از ساعت 00:00 UTC شروع می‌شوند. مدل دیگری بلافاصله پاسخ می‌دهد.
429 … temporarily busy بله. چند ثانیه صبر کنید، و در هر تلاش بعدی بیشتر.
500, 502, 503 بله. 1 ثانیه صبر کنید، سپس 2، 4 و 8. پس از چند تلاش متوقف شوید و شناسه درخواست را گزارش کنید.
504 بله. آن را با stream برابر true بفرستید: محدودیت زمانی برای پاسخ‌هایی اعمال می‌شود که stream نمی‌شوند.

یک حلقه تلاش دوباره که از این جدول پیروی می‌کند:

import re
import time

import openai
from openai import OpenAI

# max_retries=0: this loop does the retrying, the SDK does not add its own.
client = OpenAI(api_key="YOUR_API_KEY", base_url="https://api.shannon-ai.com/v1", max_retries=0)


def create_with_retry(attempts=5, **request):
    for attempt in range(attempts):
        try:
            return client.chat.completions.create(**request)
        except openai.RateLimitError as error:
            text = str(error)
            flood = re.search(r"Retry in (\d+)s", text)
            if flood:
                time.sleep(int(flood.group(1)))   # flood protection: wait out the minute
            elif "temporarily busy" in text:
                time.sleep(2 ** attempt)
            else:
                raise                             # balance: a wait of seconds does not help
        except (openai.InternalServerError, openai.APIConnectionError):
            time.sleep(2 ** attempt)              # 1, 2, 4, 8 seconds
    raise RuntimeError("the request failed after all attempts")


response = create_with_retry(
    model="shannon-3",
    messages=[{"role": "user", "content": "Hello"}],
)
print(response.choices[0].message.content)

خطاها داخل یک stream

stream از اولین بایت وضعیت 200 دارد. شکست پس از آن به‌صورت یک رویداد داخل stream می‌رسد: یک chunk با عضو error روی /v1/chat/completions، یک رویداد error روی /v1/messages، یک رویداد response.failed یا error روی /v1/responses. رویدادهای پایانی stream همچنان بعد از آن می‌آیند. چنین پاسخی را ناموفق در نظر بگیرید و درخواست را دوباره بفرستید، مانند وضعیت 5xx.

گفتگویی که از پنجره زمینه مدل بلندتر باشد به همین شکل، با نوع invalid_request_error و کد context_length_exceeded، گزارش می‌شود. پیش از ارسال دوباره، گفتگو را کوتاه کنید.

فریم‌های دقیق همراه با streaming توضیح داده شده‌اند. استریم

شناسه‌های درخواست

هر پاسخ، از جمله خطاها، هدر x-request-id دارد. مقداری است که در هدر x-request-id خودتان فرستاده‌اید، یا 12 نویسه هگزادسیمال اگر چیزی نفرستاده باشید. آن را لاگ کنید و هنگام درخواست کمک درباره یک درخواست ذکر کنید.