Penanganan kesalahan
Permintaan yang gagal mengembalikan kode status HTTP dan body JSON dengan tipe error dan pesan. Halaman ini mencantumkan setiap status, menunjukkan isi error dari setiap format API, dan menyebutkan error mana yang layak dikirim ulang.
SDK memunculkan objek error yang membawa kode status dan field dari body. Permintaan ini menyebutkan model yang tidak ada:
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"}]
}' Permintaan ini mengembalikan status 400 dan body berikut:
{
"error": {
"type": "invalid_request_error",
"message": "unknown model: no-such-model"
}
} Isi error
Ada dua bentuk body. /v1/messages menjawab dalam format Anthropic; semua endpoint lain menjawab dalam format OpenAI. Pada keduanya, rinciannya ada di error.type dan error.message, sehingga satu pembaca melayani semua endpoint.
{
"error": {
"type": "authentication_error",
"message": "Invalid API key",
"code": "invalid_api_key",
"param": null
}
} {
"type": "error",
"error": {
"type": "authentication_error",
"message": "Invalid API key"
}
} | Field | Tipe | Deskripsi |
|---|---|---|
error.type | string | Jenis error. Lihat Tipe error di bawah. |
error.message | string | Kalimat untuk manusia. Teks dalam tabel di bawah stabil kecuali bagian variabelnya, yang ditampilkan sebagai <id>, <n>, atau …. |
error.code | string | null | Ada pada beberapa error format OpenAI: invalid_api_key dengan 401, request_too_large dengan 413, context_length_exceeded ketika percakapan terlalu panjang, selain itu null atau tidak ada. Putuskan berdasarkan status dan error.type lebih dulu dan perlakukan code sebagai tambahan. |
error.param | null | Ada pada error yang sama dengan code. Selalu null. |
type | string | Hanya format Anthropic. Selalu error. |
Tipe error
| Tipe | Status | Deskripsi |
|---|---|---|
invalid_request_error | 400, 413, 415, 422 | Permintaan itu sendiri salah: sebuah field, body, id model, atau input yang tidak diterima model. Ubah permintaan sebelum Anda mengirimnya lagi. |
authentication_error | 401 | API key tidak ada, tidak dikenal, atau sudah dicabut. |
not_found_error | 404 | Path tidak ada. |
rate_limit_error | 429 | Saldo tidak mencukupi permintaan, flood protection menghentikannya, atau model sedang sibuk. Pesannya menyebutkan yang mana. |
api_error | 500, 502, 503, 504 | Permintaan sudah benar dan kegagalan ada di sisi kami. Kirim ulang. |
server_error | 500 | Permintaan sudah benar dan kegagalan ada di sisi kami. Kirim ulang. |
Kode status
| Status | Tipe | Pesan | Kapan |
|---|---|---|---|
400 | invalid_request_error | Failed to parse the request body as JSON: … | Body bukan JSON yang valid. |
400 | invalid_request_error | unknown model: <id> | model bukan id yang dipublikasikan. Di /v1/responses juga ketika model tidak ada. |
400 | invalid_request_error | No user message provided | Tingkat Shannon: permintaan tidak berisi teks pengguna. |
400 | invalid_request_error | <id> does not accept image input | Gambar dikirim ke model open-weight hosted yang tidak mendukung input gambar. |
400 | invalid_request_error | audio and video input are not supported by any hosted model | Bagian audio atau video dikirim ke model open-weight hosted. |
400 | invalid_request_error | <id> does not accept response_format | Output terstruktur diminta dari model open-weight hosted yang tidak mendukungnya. |
400 | invalid_request_error | <id> does not accept response_format json_schema; use json_object | JSON schema dikirim ke model open-weight hosted yang hanya menerima json_object. |
400 | invalid_request_error | unknown reasoning effort '<value>'; expected off, low, medium or high | Reasoning effort bukan salah satu nilai yang tercantum. Model open-weight hosted. |
400 | invalid_request_error | count_tokens is available for the hosted open models; unknown model: <id> | Penghitungan token diminta untuk model di luar model open-weight hosted. |
401 | authentication_error | Missing authentication | API key tidak dikirim. |
401 | authentication_error | Invalid API key | Kunci tidak dikenal, sudah diganti dengan yang lebih baru, atau sudah dicabut. |
404 | not_found_error | Not Found | Path tidak ada, misalnya /v1/embeddings. |
405 | api_error | Method Not Allowed | Path ada tetapi tidak dengan metode HTTP ini. |
413 | invalid_request_error | Failed to buffer the request body: … | Body permintaan lebih besar dari 32 MiB. |
415 | invalid_request_error | Expected request with `Content-Type: application/json` | Header Content-Type tidak ada atau bukan application/json. |
422 | invalid_request_error | Failed to deserialize the JSON body into the target type: … | Field wajib tidak ada, seperti messages, atau sebuah field memiliki tipe JSON yang salah. |
429 | rate_limit_error | Quota exceeded. Upgrade your plan at shannon-ai.com/plan | Batas output permintaan lebih besar daripada sisa saldo Anda. |
429 | rate_limit_error | Too many requests. Retry in <n>s. | Flood protection: lebih dari 120 permintaan dalam satu menit pada akun Anda. <n> adalah jumlah detik sampai menit berakhir. |
429 | rate_limit_error | Shannon Coder call quota reached. Upgrade your plan at shannon-ai.com/plan | shannon-coder-1 di /v1/chat/completions dan /v1/messages: panggilan Shannon Coder dari paket Anda untuk jendela 4 jam saat ini sudah habis. |
429 | rate_limit_error | Shannon routes are temporarily busy. Please retry. | Model sedang sibuk saat ini. |
500 | server_error | The model backend failed to answer. Please retry. | Model tidak menghasilkan balasan. |
500 | server_error | An internal error occurred. Please retry. | Kegagalan internal saat permintaan disiapkan. |
502 | api_error | The model backend failed to answer. Please retry. | Model tidak menghasilkan balasan. Keluarga Shannon 3 dan model open-weight hosted. |
503 | api_error | Could not verify your quota right now. Please retry. | Saldo Anda tidak dapat dibaca saat ini. |
503 | api_error | token counting is temporarily unavailable for this model | Penghitungan token tidak tersedia untuk model ini saat ini. |
504 | api_error | upstream timed out | Model open-weight hosted memerlukan waktu lebih lama daripada batas waktu untuk permintaan tanpa streaming. |
Pemeriksaan berjalan dalam urutan ini: API key, body permintaan, id model, flood protection, saldo. Permintaan dengan kunci salah dan body salah karena itu mengembalikan 401. Permintaan yang ditolak dengan status 4xx tidak dikenai biaya.
Saldo dan flood protection
Setiap permintaan dilayani setara: tidak ada tingkat rate dan tidak ada kuota API terpisah. Dua hal tetap dapat dijawab dengan 429, keduanya dengan tipe rate_limit_error. Pesannya membedakan keduanya.
Saldo
Saldo Anda adalah kuota paket hari ini, yang direset pukul 00:00 UTC, dan setelahnya kredit yang Anda beli. Chat dan API menarik dari saldo yang sama.
Setiap permintaan lebih dulu mencadangkan batas outputnya: max_tokens, atau max_output_tokens di /v1/responses, 4,096 jika Anda tidak mengirim keduanya. Ketika balasan selesai, jumlah yang dicadangkan diganti dengan yang dipakai permintaan. Jika jumlah itu tidak muat dalam saldo yang tersisa, permintaan mengembalikan Quota exceeded sebelum model mulai.
Permintaan yang berjalan bersamaan masing-masing mencadangkan jumlahnya sendiri. Banyak permintaan paralel dengan max_tokens tinggi karena itu dapat menghabiskan saldo untuk sesaat, meskipun setiap balasan pendek. max_tokens yang lebih rendah mencadangkan lebih sedikit.
Flood protection
Flood protection mengizinkan 120 permintaan per menit per akun. Ia menghitung akun, bukan kunci, pada /v1/chat/completions, /v1/responses, dan /v1/messages secara bersama-sama. Menit dimulai dengan permintaan pertama Anda.
Permintaan nomor 121 dalam menit itu mengembalikan Too many requests. Retry in <n>s. dan tidak dikenai biaya. Permintaan yang ditolak juga dihitung, sehingga klien yang mengirim ulang tanpa menunggu tetap ditolak sampai menit berakhir. Tunggu sebanyak <n> detik dari pesan.
Permintaan yang dikirim paralel tidak ditolak hanya karena paralel. Permintaan itu mengantre dan dijawab bergiliran.
GET /v1/models dan endpoint penghitungan token tidak dihitung.
Selengkapnya tentang batas dan saldo, serta tempat melihat saldo dan penggunaan Anda sendiri: Batas dan saldo Keys & usage
Apa yang perlu dicoba ulang
Kirim ulang permintaan hanya jika permintaan yang sama dapat berhasil. SDK OpenAI dan Anthropic sudah mencoba ulang balasan 429 dan 5xx dua kali secara otomatis; atur max_retries (maxRetries di JavaScript) untuk mengubahnya.
| Error | Kirim ulang? | Caranya |
|---|---|---|
400, 404, 405, 413, 415, 422 | Tidak. Perbaiki permintaan terlebih dahulu. | Pesan menyebutkan field, model, atau input yang salah. |
401 | Tidak. Gunakan kunci yang valid. | Buat atau ganti kunci di halaman Keys & usage. |
429 Too many requests | Ya, setelah menunggu. | Tunggu sejumlah detik yang tertera dalam pesan, lalu kirim permintaan yang sama. |
429 Quota exceeded | Tidak apa adanya. | Turunkan max_tokens, tunggu reset harian pukul 00:00 UTC, atau tambah kredit. |
429 Shannon Coder call quota reached | Ya, di jendela berikutnya. | Jendela dimulai setiap 4 jam dari pukul 00:00 UTC. Model lain langsung menjawab. |
429 … temporarily busy | Ya. | Tunggu beberapa detik, lalu lebih lama pada setiap percobaan berikutnya. |
500, 502, 503 | Ya. | Tunggu 1 detik, lalu 2, 4, dan 8. Berhenti setelah beberapa percobaan dan laporkan id permintaan. |
504 | Ya. | Kirim dengan stream diatur ke true: batas waktu berlaku untuk balasan tanpa streaming. |
Loop retry yang mengikuti tabel ini:
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); Error di dalam stream
Stream berstatus 200 sejak byte pertamanya. Kegagalan setelah itu tiba sebagai event di dalam stream: chunk dengan member error di /v1/chat/completions, event error di /v1/messages, event response.failed atau error di /v1/responses. Event penutup stream tetap menyusul. Anggap balasan seperti itu gagal dan kirim permintaan sekali lagi, seperti untuk status 5xx.
Percakapan yang lebih panjang daripada jendela konteks model dilaporkan dengan cara ini, dengan tipe invalid_request_error dan kode context_length_exceeded. Persingkat percakapan sebelum Anda mengirimnya lagi.
Frame yang tepat dijelaskan bersama streaming. Streaming
Id permintaan
Setiap balasan, termasuk error, memiliki header x-request-id. Nilainya adalah yang Anda kirim di header x-request-id Anda sendiri, atau 12 karakter heksadesimal jika Anda tidak mengirim. Catat di log, dan sertakan saat Anda meminta bantuan untuk sebuah permintaan.