DokumentasiReferensi API

Error dan status

Bentuk error, tabel kode, dan cara menanganinya.

Ringkasan

Setiap kegagalan dijawab dengan bentuk JSON yang sama, dan code di dalamnya yang menentukan apa yang harus kamu lakukan.

bentuk error
{
  "error": {
    "message": "Pesan yang aman untuk ditampilkan.",
    "type": "invalid_request_error",
    "code": "model_not_found"
  }
}

Body-nya selalu JSON. Status HTTP memberi tahu kelasnya, dan code memberi tahu yang sebenarnya terjadi. Percayai code, karena satu status bisa berarti dua hal berbeda.

Di permukaan Anthropic (POST /v1/messages), error memakai envelope Anthropic, dan validation di sana 400, bukan 422. Lihat Format Anthropic.

Tabel error

HTTPtypecodeArtinya
400invalid_request_errorinvalid_requestRequest tidak bisa diproses.
401authentication_errorinvalid_api_keyAPI key hilang atau tidak dikenali.
401authentication_errornot_authenticatedSesi konsol tidak ada atau sudah berakhir.
401authentication_errorinvalid_credentialsEmail atau kata sandi salah saat masuk.
402billing_errorinsufficient_balanceSaldo dompet tidak cukup.
402billing_errorspending_limit_exceededBatas belanja key ini sudah habis.
403permission_errorforbiddenTidak diizinkan untuk tindakan ini.
404invalid_request_errormodel_not_foundModel tidak ada, atau path-nya tidak cocok dengan rute mana pun.
409invalid_request_errorconflictBertentangan dengan keadaan saat ini.
413invalid_request_errorrequest_too_largeBody request melewati batas ukuran (30 MiB).
422invalid_request_errorinvalid_requestBody request gagal validasi.
429rate_limit_errorrate_limit_exceededBatas per menit terlewati.
429rate_limit_errorconcurrency_exceededBatas request bersamaan terlewati.
500server_errorinternal_errorKesalahan di sisi kami.
501server_errornot_implementedRutenya ada, kemampuannya belum dibangun.
502server_errorempty_completionModel menjawab, tokennya sudah diproses, tapi tidak ada output yang bisa dibaca.
502server_errorupstream_unavailableModel di balik layar tidak bisa dihubungi.
504server_errorupstream_timeoutModel di balik layar kehabisan waktu.

Empat yang perlu diperhatikan

empty_completion punya aturan biaya sendiri, dan itu mengikuti apakah tokenmu sempat diproses. Model menjawab 200 tapi tidak menghasilkan apa pun yang bisa dibaca. Kalau ada pemakaian yang tercatat, NusaRouter tetap menagihkan token yang sudah diproses, dan pesan errornya menyebutkan itu. Kalau tidak ada pemakaian yang tercatat, penahanannya dilepas penuh. Ia sengaja dibedakan dari upstream_unavailable: yang satu berarti modelnya jalan tapi tidak bicara, yang lain berarti modelnya tidak bisa dihubungi. Yang pertama kamu ulangi atau naikkan max_tokens; yang kedua kamu tunggu.

not_implemented (501) berbeda dari internal_error (500). 500 berarti sesuatu seharusnya bekerja tapi tidak. Ada gangguan. 501 berarti kemampuan itu memang belum dibangun. Kalau kamu menerima 501, mengulang tidak akan menolong.

model_not_found juga muncul untuk path yang tidak cocok dengan rute mana pun. Jadi kalau kamu salah mengetik path (misalnya lupa /v1), yang muncul model_not_found, bukan pesan tentang rute. Periksa URL-nya sebelum menyimpulkan bahwa id modelmu salah.

concurrency_exceeded berarti ada requestmu yang masih berjalan. Ia berbagi status 429 dengan rate_limit_exceeded, tapi penanganannya berbeda: yang pertama diatasi dengan membatasi paralelisme, yang kedua dengan menunggu.

Yang tidak pernah kami kirim

Pesan error dibangun dari daftar kode yang tetap. Teks mentah dari model di balik layar tidak pernah diteruskan apa adanya, karena teks itu sering memantulkan konteks request. Di dalamnya bisa ada alamat internal, nama host, dan referensi akun.

Kalau sesuatu gagal di sisi kami, yang kamu terima pesan umum dengan status 500. Detailnya masuk ke log kami, bukan ke responsemu. Itu disengaja: detail internal di response cara paling umum sebuah sistem membocorkan dirinya sendiri.

Menangani error

Python
import time
from openai import OpenAI, APIStatusError

client = OpenAI(base_url="https://api.nusarouter.web.id/v1", api_key="sk-nusa-...")

for attempt in range(5):
    try:
        r = client.chat.completions.create(
            model="deepseek-flash-v4.1",
            messages=[{"role": "user", "content": "Halo!"}],
        )
        break
    except APIStatusError as e:
        body = e.response.json().get("error", {})
        code = body.get("code")

        # Yang tidak akan membaik dengan diulang: hentikan, jangan ulangi.
        if code in ("invalid_request", "model_not_found", "insufficient_balance",
                    "spending_limit_exceeded", "not_implemented"):
            raise

        # Batas laju: ikuti retry-after, jangan menebak jedanya.
        if e.status_code == 429:
            time.sleep(float(e.response.headers.get("retry-after", "1")))
            continue

        # 5xx dari sisi kami: mundur eksponensial.
        time.sleep(2 ** attempt)
else:
    raise RuntimeError("menyerah setelah 5 percobaan")

Aturan yang paling sering diabaikan: jangan mengulang error yang tidak akan membaik dengan diulang. Mengulang invalid_request atau model_not_found hanya menghasilkan request yang sama gagal berkali-kali, dan untuk error saldo ia menambah beban tanpa mengubah apa pun.

Troubleshooting

GejalaPenyebabSolusi
401Key tidak terkirim atau sudah dicabut.lihat Autentikasi
404 model_not_foundId model salah, atau path-nya tidak cocok dengan rute mana pun.cek id dari katalog, dan cek URL-nya berakhir /v1/chat/completions
402Saldo dompet habis, atau batas belanja key habis.lihat code-nya: insufficient_balance berarti top up, spending_limit_exceeded berarti naikkan batas key
429Batas per menit atau batas konkurensi.tunggu retry-after, atau batasi paralelisme; lihat Batas laju
502Model tidak bisa dihubungi (upstream_unavailable), atau menjawab tanpa output yang bisa dibaca (empty_completion).cek pesan errornya untuk tahu yang mana. Kalau pesannya menyebut biaya, mengulang berarti membayar lagi, jadi perbaiki dulu penyebabnya
504Model kehabisan waktu.ulangi dengan request yang lebih pendek, atau tanpa streaming untuk jawaban panjang