معالجة الأخطاء
الطلب الذي يفشل يعيد رمز حالة HTTP ونص JSON فيه نوع الخطأ ورسالة. تسرد هذه الصفحة كل حالة، وتعرض نص الخطأ في كل صيغة API، وتبيّن أي الأخطاء تستحق إعادة الإرسال.
ترفع الحزم كائن خطأ يحمل رمز الحالة وحقول النص. يسمّي هذا الطلب نموذجاً غير موجود:
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 import OpenAI from "openai";
const client = new OpenAI({
apiKey: "YOUR_API_KEY",
baseURL: "https://api.shannon-ai.com/v1",
});
try {
await client.chat.completions.create({
model: "no-such-model",
messages: [{ role: "user", content: "Hello" }],
});
} catch (error) {
if (!(error instanceof OpenAI.APIError)) throw error;
console.log(error.status); // 400
console.log(error.type); // invalid_request_error
console.log(error.error.message); // unknown model: no-such-model
} curl -i https://api.shannon-ai.com/v1/chat/completions \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "no-such-model",
"messages": [{"role": "user", "content": "Hello"}]
}' يعيد الحالة 400 وهذا النص:
{
"error": {
"type": "invalid_request_error",
"message": "unknown model: no-such-model"
}
} نص الخطأ
هناك نصّان. يجيب /v1/messages بصيغة Anthropic؛ وتجيب كل نقطة نهاية أخرى بصيغة OpenAI. في الاثنين تكون التفاصيل في error.type وerror.message، فيخدم قارئ واحد كل نقاط النهاية.
{
"error": {
"type": "authentication_error",
"message": "Invalid API key",
"code": "invalid_api_key",
"param": null
}
} {
"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 | أُرسلت صورة إلى نموذج مفتوح الأوزان مستضاف لا يدعم إدخال الصور. |
400 | invalid_request_error | audio and video input are not supported by any hosted model | أُرسل جزء صوت أو فيديو إلى نموذج مفتوح الأوزان مستضاف. |
400 | invalid_request_error | <id> does not accept response_format | طُلبت مخرجات منظمة من نموذج مفتوح الأوزان مستضاف لا يدعمها. |
400 | invalid_request_error | <id> does not accept response_format json_schema; use json_object | أُرسل مخطط JSON إلى نموذج مفتوح الأوزان مستضاف لا يقبل سوى json_object. |
400 | invalid_request_error | unknown reasoning effort '<value>'; expected off, low, medium or high | جهد الاستدلال ليس إحدى القيم المذكورة. النماذج المفتوحة الأوزان المستضافة. |
400 | invalid_request_error | count_tokens is available for the hosted open models; unknown model: <id> | طُلب عدّ tokens لنموذج من خارج النماذج المفتوحة الأوزان المستضافة. |
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. | الحماية من الإغراق: أكثر من 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 والنماذج المفتوحة الأوزان المستضافة. |
503 | api_error | Could not verify your quota right now. Please retry. | تعذرت قراءة رصيدك في هذه اللحظة. |
503 | api_error | token counting is temporarily unavailable for this model | عدّ tokens غير متاح لهذا النموذج في هذه اللحظة. |
504 | api_error | upstream timed out | استغرق نموذج مفتوح الأوزان مستضاف وقتاً أطول من الحد الزمني لطلب غير مبثوث. |
تجري الفحوص بهذا الترتيب: مفتاح 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 أقل يحجز مقداراً أقل.
الحماية من الإغراق
تسمح الحماية من الإغراق بـ 120 طلباً في الدقيقة لكل حساب. وهي تحسب الحساب لا المفتاح، عبر /v1/chat/completions و/v1/responses و/v1/messages معاً. وتبدأ الدقيقة مع أول طلب منك.
الطلب رقم 121 ضمن تلك الدقيقة يعيد Too many requests. Retry in <n>s. ولا يكلف شيئاً. والطلبات المرفوضة تُحتسب أيضاً، لذا يبقى العميل الذي يعيد الإرسال دون انتظار مرفوضاً حتى تنتهي الدقيقة. انتظر <n> ثانية المذكورة في الرسالة.
الطلبات المرسلة بالتوازي لا تُرفض لكونها متوازية. إنما تنتظر في الطابور ويُجاب عنها بالدور.
لا يُحتسب GET /v1/models ولا نقاط نهاية عدّ tokens.
المزيد عن الحدود والرصيد، وأين ترى رصيدك واستخدامك: الحدود والرصيد المفاتيح والاستخدام
ما الذي تُعاد محاولته
أعد إرسال الطلب فقط عندما يمكن للطلب نفسه أن ينجح. تعيد حزم OpenAI وAnthropic SDK محاولة ردود 429 و5xx مرتين من تلقاء نفسها؛ اضبط max_retries (maxRetries في JavaScript) لتغيير ذلك.
| الخطأ | هل تُعاد المحاولة؟ | كيف |
|---|---|---|
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: فالحد الزمني يسري على الردود غير المبثوثة. |
حلقة إعادة محاولة تتبع هذا الجدول:
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) import OpenAI from "openai";
// maxRetries: 0 — this loop does the retrying, the SDK does not add its own.
const client = new OpenAI({ apiKey: "YOUR_API_KEY", baseURL: "https://api.shannon-ai.com/v1", maxRetries: 0 });
const sleep = (seconds) => new Promise((resolve) => setTimeout(resolve, seconds * 1000));
async function createWithRetry(request, attempts = 5) {
for (let attempt = 0; attempt < attempts; attempt++) {
try {
return await client.chat.completions.create(request);
} catch (error) {
const text = String(error.message);
const flood = text.match(/Retry in (\d+)s/);
if (error.status === 429 && flood) {
await sleep(Number(flood[1])); // flood protection: wait out the minute
} else if (error.status === 429 && text.includes("temporarily busy")) {
await sleep(2 ** attempt);
} else if (error.status >= 500 || error instanceof OpenAI.APIConnectionError) {
await sleep(2 ** attempt); // 1, 2, 4, 8 seconds
} else {
throw error; // wrong request, wrong key or balance
}
}
}
throw new Error("the request failed after all attempts");
}
const response = await createWithRetry({
model: "shannon-3",
messages: [{ role: "user", content: "Hello" }],
});
console.log(response.choices[0].message.content); الأخطاء داخل البث
للبث الحالة 200 منذ أول بايت. والفشل بعد ذلك يصل كحدث داخل البث: جزء فيه عضو error على /v1/chat/completions، أو حدث error على /v1/messages، أو حدث response.failed أو error على /v1/responses. وتتبعه أحداث إغلاق البث. اعتبر ردّاً كهذا فاشلاً وأعد إرسال الطلب، كما في حالة 5xx.
المحادثة الأطول من نافذة سياق النموذج يُبلَّغ عنها بهذه الطريقة، بالنوع invalid_request_error والرمز context_length_exceeded. قصّر المحادثة قبل أن ترسلها من جديد.
الإطارات بالتفصيل موصوفة مع البث. البث
معرّفات الطلبات
كل رد، بما فيه الأخطاء، يحمل ترويسة x-request-id. وهي القيمة التي أرسلتها في ترويستك x-request-id، أو 12 رمزاً سداسياً عشرياً إن لم ترسل شيئاً. سجّلها، واذكرها عند طلب المساعدة بشأن طلب.