خطاها و کدهای خطا
فهرست کامل کدهای خطای API هوشوانا با وضعیت HTTP، معنی و راهحل هر کدام، به همراه راهنمای تلاش دوباره و نمونهکد مدیریت خطا در Python و Node.js.
آخرین بهروزرسانی:
وقتی درخواستی به API هوشوانا با مشکل روبهرو شود، پاسخ یک کد وضعیت HTTP غیر ۲۰۰ و یک بدنهی JSON با جزئیات خطا دارد. این صفحه همهی کدهای خطا و کاری را که باید در هر مورد انجام دهید توضیح میدهد.
قالب خطا
قالب خطا با OpenAI سازگار است، بنابراین SDKها آن را بهدرستی تشخیص میدهند. پیام خطا به فارسی است تا بتوانید آن را مستقیم در لاگها بخوانید:
{
"error": {
"message": "موجودی کیف پول برای این درخواست کافی نیست. لطفاً حساب خود را شارژ کنید.",
"type": "billing_error",
"code": "insufficient_balance"
}
}code: شناسهی پایدار خطا. منطق برنامه را بر اساس این فیلد بنویسید.message: توضیح قابل خواندن برای انسان. ممکن است متنش تغییر کند، پس در کد به آن وابسته نشوید.type: دستهی کلی خطا.
جدول کدهای خطا
| کد | HTTP | معنی | چه کار کنید |
|---|---|---|---|
invalid_request | 400 | درخواست نامعتبر است: فیلد الزامی ندارد، نوع داده اشتباه است یا پارامتری با مدل سازگار نیست | پیام خطا را بخوانید و بدنه را اصلاح کنید. تلاش دوباره بیفایده است |
invalid_api_key | 401 | کلید ارسال نشده، اشتباه است یا باطل شده | هدر Authorization یا x-api-key و مقدار متغیر محیطی را بررسی کنید |
insufficient_balance | 402 | موجودی کیف پول کمتر از حداقل لازم یا هزینهی تخمینی درخواست است | کیف پول را شارژ کنید یا max_tokens را کم کنید |
spend_cap_reached | 402 | سقف هزینهی روزانه، ماهانه یا بودجهی کل کلید یا حساب پر شده | تا دورهی بعد صبر کنید یا سقف را در قوانین افزایش دهید |
key_paused | 403 | کلید موقتاً متوقف شده است | کلید را در داشبورد دوباره فعال کنید |
key_expired | 403 | تاریخ انقضای کلید گذشته است | کلید جدید بسازید یا تاریخ انقضا را تمدید کنید |
ip_not_allowed | 403 | IP یا referrer درخواست در فهرست مجاز کلید نیست | IP سرور را به فهرست مجاز اضافه کنید |
endpoint_not_allowed | 403 | کلید اجازهی استفاده از این endpoint را ندارد | endpoint را در قوانین کلید مجاز کنید یا از کلید دیگری استفاده کنید |
model_not_allowed | 403 | مدل وجود دارد ولی قوانین کلید یا حساب آن را مجاز نمیدانند | مدل یا گروهش را در قوانین مجاز کنید یا مدل مجاز دیگری انتخاب کنید |
model_not_found | 404 | شناسهی مدل اشتباه است یا مدل در دسترس نیست | شناسه را با GET /models یا کاتالوگ مدلها مقایسه کنید |
rate_limited | 429 | از محدودیت تعداد درخواست یا توکن در دقیقه عبور کردهاید | پس از مدت هدر Retry-After با backoff تلاش کنید. محدودیت نرخ |
upstream_error | 502 | ارائهدهندهی مدل خطا داده و جایگزین خودکار هم موفق نبوده | با backoff دوباره تلاش کنید. اگر ادامه داشت، وضعیت سرویس را ببینید |
upstream_timeout | 504 | ارائهدهندهی مدل در زمان مقرر پاسخ نداده | دوباره تلاش کنید، از استریم استفاده کنید یا ورودی را کوتاهتر کنید |
ترتیب بررسی قوانین که مشخص میکند کدام خطا زودتر برمیگردد، در قوانین کلید آمده است.
کدام خطاها ارزش تلاش دوباره دارند؟
| دسته | کدها | تلاش دوباره؟ |
|---|---|---|
| موقتی | rate_limited، upstream_error، upstream_timeout | بله، با backoff نمایی |
| مالی | insufficient_balance، spend_cap_reached | خیر، تا وقتی موجودی یا سقف تغییر نکند |
| دسترسی و تنظیمات | invalid_api_key، key_paused، key_expired، ip_not_allowed، endpoint_not_allowed، model_not_allowed | خیر، تنظیمات را اصلاح کنید |
| درخواست | invalid_request، model_not_found | خیر، درخواست را اصلاح کنید |
هوشوانا خودش در صورت مشکل یک ارائهدهنده، درخواست را به مسیرهای جایگزین میفرستد. پس وقتی upstream_error میگیرید، یعنی این تلاشهای خودکار هم موفق نبودهاند و چند ثانیه صبر قبل از تلاش دوباره منطقی است.
مدیریت خطا در Python
SDK رسمی OpenAI برای خطاها کلاسهای مشخص دارد. کد هوشوانا در e.code (یا داخل e.body) در دسترس است:
import os
import random
import time
import openai
from openai import OpenAI
client = OpenAI(
base_url="https://hooshvana.ir/api/v1",
api_key=os.environ["HOOSHVANA_API_KEY"],
max_retries=0, # we handle retries ourselves below
)
RETRYABLE = {"rate_limited", "upstream_error", "upstream_timeout"}
def chat(messages, model="openai/gpt-4o-mini", attempts=5):
for attempt in range(attempts):
try:
return client.chat.completions.create(model=model, messages=messages)
except openai.APIStatusError as e:
code = getattr(e, "code", None)
request_id = e.response.headers.get("x-hooshvana-request-id")
if code not in RETRYABLE or attempt == attempts - 1:
print(f"failed: status={e.status_code} code={code} request_id={request_id}")
raise
retry_after = e.response.headers.get("retry-after")
delay = float(retry_after) if retry_after else min(30, 2 ** attempt) + random.random()
time.sleep(delay)
except openai.APIConnectionError:
if attempt == attempts - 1:
raise
time.sleep(min(30, 2 ** attempt) + random.random())
try:
reply = chat([{"role": "user", "content": "سلام"}])
print(reply.choices[0].message.content)
except openai.APIStatusError as e:
if getattr(e, "code", None) == "insufficient_balance":
print("Please top up the wallet.")SDK بهطور پیشفرض خودش چند بار روی خطاهای ۴۲۹ و ۵xx تلاش دوباره میکند. اگر منطق خودتان را مینویسید، مثل نمونهی بالا max_retries=0 بگذارید تا تلاشها دو برابر نشوند.
مدیریت خطا در Node.js
import OpenAI from "openai";
const client = new OpenAI({
baseURL: "https://hooshvana.ir/api/v1",
apiKey: process.env.HOOSHVANA_API_KEY,
maxRetries: 0,
});
const RETRYABLE = new Set(["rate_limited", "upstream_error", "upstream_timeout"]);
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
// Works with both SDK v4 (plain object) and v5 (Headers instance)
const header = (h, name) => (typeof h?.get === "function" ? h.get(name) : h?.[name]);
async function chat(messages, model = "openai/gpt-4o-mini", attempts = 5) {
for (let attempt = 0; attempt < attempts; attempt++) {
try {
return await client.chat.completions.create({ model, messages });
} catch (err) {
if (!(err instanceof OpenAI.APIError)) throw err;
const code = err.code;
const requestId = header(err.headers, "x-hooshvana-request-id");
const retryable = RETRYABLE.has(code) || err instanceof OpenAI.APIConnectionError;
if (!retryable || attempt === attempts - 1) {
console.error("failed", { status: err.status, code, requestId, message: err.message });
throw err;
}
const retryAfter = Number(header(err.headers, "retry-after"));
const delay = retryAfter > 0
? retryAfter * 1000
: Math.min(30000, 2 ** attempt * 1000) + Math.random() * 1000;
await sleep(delay);
}
}
}
const reply = await chat([{ role: "user", content: "سلام" }]);
console.log(reply.choices[0].message.content);خطا در میانهی استریم
اگر استریم شروع شده باشد و بعد خطایی رخ دهد، کد وضعیت HTTP دیگر قابل تغییر نیست (۲۰۰ ارسال شده است). در این حالت یک رویداد خطا در استریم ارسال و اتصال بسته میشود. SDKها این رویداد را به استثنا تبدیل میکنند. حلقهی خواندن استریم را در try قرار دهید و در صورت خطا، متن جزئی را یا دور بریزید یا به کاربر اطلاع دهید که پاسخ ناقص است.
نکتههای کاربردی
- همیشه
x-hooshvana-request-idرا همراه خطا در لاگ برنامهی خود ثبت کنید. با آن میتوانید درخواست را در لاگ درخواستها پیدا کنید. - پیام خطای فارسی را میتوانید به کاربر نهایی هم نشان دهید، ولی برای خطاهای مالی یا دسترسی، پیام عمومیتری نمایش دهید و جزئیات را فقط در لاگ نگه دارید.
- برای جلوگیری از توقف سرویس به خاطر
insufficient_balance، آستانهی هشدار موجودی کم را در تنظیمات حساب فعال کنید.