Przejdź do treści
Obsługa błędów

Obsługa błędów

Zapytanie, które się nie powiedzie, zwraca kod statusu HTTP i treść JSON z typem błędu i komunikatem. Ta strona wymienia każdy status, pokazuje treść błędu w każdym formacie API i mówi, które błędy warto wysłać ponownie.

SDK zgłaszają obiekt błędu, który niesie kod statusu i pola treści. To zapytanie podaje model, który nie istnieje:

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

Zwraca status 400 i tę treść:

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

Treść błędu

Są dwie treści błędu. /v1/messages odpowiada w formacie Anthropic; każdy inny endpoint odpowiada w formacie OpenAI. W obu szczegóły są w error.type i error.message, więc jeden czytnik obsługuje wszystkie endpointy.

401 Format OpenAI
{
  "error": {
    "type": "authentication_error",
    "message": "Invalid API key",
    "code": "invalid_api_key",
    "param": null
  }
}
401 Format Anthropic
{
  "type": "error",
  "error": {
    "type": "authentication_error",
    "message": "Invalid API key"
  }
}
Pole Typ Opis
error.type string Rodzaj błędu. Zobacz niżej Typy błędów.
error.message string Zdanie dla człowieka. Teksty w tabelach poniżej są stałe aż do części zmiennych, pokazanych jako <id>, <n> lub ….
error.code string | null Obecne w niektórych błędach formatu OpenAI: invalid_api_key z 401, request_too_large z 413, context_length_exceeded, gdy rozmowa jest zbyt długa, poza tym null lub brak. Najpierw decyduj według statusu i error.type, a code traktuj jako dodatek.
error.param null Obecne w tych samych błędach co code. Zawsze null.
type string Tylko format Anthropic. Zawsze error.

Typy błędów

Typ Statusy Opis
invalid_request_error 400, 413, 415, 422 Samo zapytanie jest błędne: pole, treść, id modelu lub wejście, którego model nie przyjmuje. Zmień zapytanie, zanim wyślesz je ponownie.
authentication_error 401 Klucz API jest nieobecny, nieznany lub unieważniony.
not_found_error 404 Ścieżka nie istnieje.
rate_limit_error 429 Saldo nie pokrywa zapytania, zatrzymała je ochrona przed floodem albo model jest zajęty. Komunikat mówi, które z tych.
api_error 500, 502, 503, 504 Zapytanie było poprawne, a awaria jest po naszej stronie. Wyślij je ponownie.
server_error 500 Zapytanie było poprawne, a awaria jest po naszej stronie. Wyślij je ponownie.

Kody statusu

Status Typ Komunikat Kiedy
400 invalid_request_error Failed to parse the request body as JSON: … Treść nie jest prawidłowym JSON.
400 invalid_request_error unknown model: <id> model nie jest opublikowanym id. W /v1/responses także wtedy, gdy brakuje model.
400 invalid_request_error No user message provided Poziomy Shannon: zapytanie nie zawiera tekstu użytkownika.
400 invalid_request_error <id> does not accept image input Obraz wysłano do hostowanego modelu open-weight bez obsługi obrazu na wejściu.
400 invalid_request_error audio and video input are not supported by any hosted model Część audio lub wideo wysłano do hostowanego modelu open-weight.
400 invalid_request_error <id> does not accept response_format Zażądano wyjścia strukturyzowanego od hostowanego modelu open-weight, który go nie ma.
400 invalid_request_error <id> does not accept response_format json_schema; use json_object Schemat JSON wysłano do hostowanego modelu open-weight, który przyjmuje tylko json_object.
400 invalid_request_error unknown reasoning effort '<value>'; expected off, low, medium or high Wysiłek rozumowania nie jest jedną z wymienionych wartości. Hostowane modele open-weight.
400 invalid_request_error count_tokens is available for the hosted open models; unknown model: <id> Zażądano liczenia tokenów dla modelu spoza hostowanych modeli open-weight.
401 authentication_error Missing authentication Nie wysłano klucza API.
401 authentication_error Invalid API key Klucz jest nieznany, został zastąpiony nowszym albo unieważniony.
404 not_found_error Not Found Ścieżka nie istnieje, na przykład /v1/embeddings.
405 api_error Method Not Allowed Ścieżka istnieje, ale nie z tą metodą HTTP.
413 invalid_request_error Failed to buffer the request body: … Treść zapytania jest większa niż 32 MiB.
415 invalid_request_error Expected request with `Content-Type: application/json` Brakuje nagłówka Content-Type albo nie ma on wartości application/json.
422 invalid_request_error Failed to deserialize the JSON body into the target type: … Brakuje wymaganego pola, takiego jak messages, albo pole ma zły typ JSON.
429 rate_limit_error Quota exceeded. Upgrade your plan at shannon-ai.com/plan Limit wyjścia zapytania jest większy niż to, co zostało z Twojego salda.
429 rate_limit_error Too many requests. Retry in <n>s. Ochrona przed floodem: ponad 120 zapytań w ciągu jednej minuty na Twoim koncie. <n> to liczba sekund do końca minuty.
429 rate_limit_error Shannon Coder call quota reached. Upgrade your plan at shannon-ai.com/plan shannon-coder-1 w /v1/chat/completions i /v1/messages: wywołania Shannon Coder w Twoim planie na bieżące 4-godzinne okno zostały wykorzystane.
429 rate_limit_error Shannon routes are temporarily busy. Please retry. Model jest w tej chwili zajęty.
500 server_error The model backend failed to answer. Please retry. Model nie wygenerował odpowiedzi.
500 server_error An internal error occurred. Please retry. Wewnętrzna awaria podczas przygotowywania zapytania.
502 api_error The model backend failed to answer. Please retry. Model nie wygenerował odpowiedzi. Rodzina Shannon 3 i hostowane modele open-weight.
503 api_error Could not verify your quota right now. Please retry. Nie udało się w tej chwili odczytać Twojego salda.
503 api_error token counting is temporarily unavailable for this model Liczenie tokenów nie jest w tej chwili dostępne dla tego modelu.
504 api_error upstream timed out Hostowany model open-weight potrzebował więcej czasu niż wynosi limit czasu zapytania bez streamingu.

Kontrole przebiegają w tej kolejności: klucz API, treść zapytania, id modelu, ochrona przed floodem, saldo. Zapytanie z błędnym kluczem i błędną treścią zwraca więc 401. Zapytanie odrzucone ze statusem 4xx nie jest rozliczane.

Saldo i ochrona przed floodem

Każde zapytanie jest obsługiwane jednakowo: nie ma poziomów limitów szybkości ani osobnej kwoty API. Odpowiedź 429 mogą jednak dać dwie rzeczy, obie z typem rate_limit_error. Komunikat je rozróżnia.

Saldo

Twoje saldo to dzisiejszy limit planu, który odnawia się o 00:00 UTC, a po nim zakupione środki. Czat i API czerpią z tego samego salda.

Każde zapytanie najpierw odkłada swój limit wyjścia: max_tokens lub max_output_tokens w /v1/responses, 4,096, gdy nie wyślesz żadnego. Gdy odpowiedź jest kompletna, odłożona kwota jest zastępowana tym, co zapytanie zużyło. Jeśli kwota nie mieści się w pozostałym saldzie, zapytanie zwraca Quota exceeded, zanim model zacznie pracę.

Zapytania działające w tym samym czasie odkładają każde swoją kwotę. Wiele równoległych zapytań z wysokim max_tokens może więc na chwilę wyczerpać saldo, nawet gdy każda odpowiedź jest krótka. Niższe max_tokens odkłada mniej.

Ochrona przed floodem

Ochrona przed floodem dopuszcza 120 zapytań na minutę na konto. Liczy konto, nie klucz, łącznie dla /v1/chat/completions, /v1/responses i /v1/messages. Minuta zaczyna się od Twojego pierwszego zapytania.

Zapytanie numer 121 w tej minucie zwraca Too many requests. Retry in <n>s. i nic nie kosztuje. Odrzucone zapytania też się liczą, więc klient, który wysyła ponownie bez czekania, pozostaje odrzucany do końca minuty. Poczekaj <n> sekund z komunikatu.

Zapytania wysyłane równolegle nie są odrzucane za to, że są równoległe. Czekają w kolejce i są obsługiwane po kolei.

GET /v1/models i endpointy liczenia tokenów nie są liczone.

Więcej o limitach i saldzie oraz o tym, gdzie zobaczyć własne saldo i użycie: Limity i saldo Keys & usage

Co ponawiać

Wysyłaj zapytanie ponownie tylko wtedy, gdy to samo zapytanie może się powieść. SDK OpenAI i Anthropic same ponawiają odpowiedzi 429 i 5xx dwa razy; ustaw max_retries (maxRetries w JavaScript), aby to zmienić.

Błąd Wysłać ponownie? Jak
400, 404, 405, 413, 415, 422 Nie. Najpierw popraw zapytanie. Komunikat wskazuje pole, model lub wejście, które jest błędne.
401 Nie. Użyj ważnego klucza. Utwórz lub wymień klucz na stronie Keys & usage.
429 Too many requests Tak, po oczekiwaniu. Poczekaj liczbę sekund z komunikatu, a potem wyślij to samo zapytanie.
429 Quota exceeded Nie w tej postaci. Obniż max_tokens, poczekaj na dzienny reset o 00:00 UTC albo dodaj środki.
429 Shannon Coder call quota reached Tak, w następnym oknie. Okna zaczynają się co 4 godziny od 00:00 UTC. Inny model odpowiada od razu.
429 … temporarily busy Tak. Poczekaj kilka sekund, a przy każdej kolejnej próbie dłużej.
500, 502, 503 Tak. Poczekaj 1 sekundę, potem 2, 4 i 8. Przerwij po kilku próbach i zgłoś id zapytania.
504 Tak. Wyślij je z stream ustawionym na true: limit czasu dotyczy odpowiedzi bez streamingu.

Pętla ponawiania zgodna z tą tabelą:

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)

Błędy wewnątrz strumienia

Strumień ma status 200 od pierwszego bajtu. Awaria po tym momencie przychodzi jako zdarzenie wewnątrz strumienia: fragment z polem error w /v1/chat/completions, zdarzenie error w /v1/messages, zdarzenie response.failed lub error w /v1/responses. Zdarzenia kończące strumień nadal następują. Potraktuj taką odpowiedź jako nieudaną i wyślij zapytanie ponownie, jak przy statusie 5xx.

Rozmowa dłuższa niż okno kontekstu modelu jest zgłaszana w ten sposób, z typem invalid_request_error i kodem context_length_exceeded. Skróć rozmowę, zanim wyślesz ją ponownie.

Dokładne ramki opisano przy streamingu. Streaming

Id zapytań

Każda odpowiedź, także z błędem, ma nagłówek x-request-id. Jest to wartość, którą wysłałeś we własnym nagłówku x-request-id, albo 12 znaków szesnastkowych, gdy nie wysłałeś żadnej. Zapisuj go w logu i podawaj, gdy prosisz o pomoc w sprawie zapytania.