문서

문서

오류

Kunavo는 재시도 여부를 나타내는 HTTP 상태 코드와 함께 OpenAI 형식의 오류 페이로드를 반환합니다. 표준 OpenAI SDK 오류 처리 방식을 따르면 문제없이 처리할 수 있습니다.

모든 2xx가 아닌 응답은 OpenAI 표준과 동일한 JSON 형식을 사용합니다. 프로그래밍 방식의 처리는 error.code를 기준으로 하고, 재시도 정책은 status_code를 기준으로 정하세요.

오류 페이로드

{
  "error": {
    "message": "Model 'xyz-2025' is not available",
    "type": "model_not_found",
    "code": "model_not_found",
    "param": null
  }
}
필드유형참고
messagestring사람이 읽을 수 있는 형식입니다. 로그에 기록해도 안전하며, 비밀 정보는 절대 포함하지 않습니다.
typestring대략적인 범주(authentication_error, invalid_request_error, …).
codestring세분화된 식별자입니다. 프로그래밍 방식의 분기 처리에 사용합니다.
paramstring|null오류가 특정 필드와 관련된 경우 해당 필드의 이름을 표시합니다.

HTTP 상태 코드

HTTP의미Retry?
400invalid_request_error — 요청 페이로드의 형식이 잘못되었습니다.아니요 — 요청을 수정하세요.
401authentication_error — API 키가 잘못되었거나, 누락되었거나, 취소되었습니다.아니요 — 키를 교체하세요.
402insufficient_quota — 지갑 잔액이 없거나(code: insufficient_balance), 월간 한도에 도달했습니다.아니요 — /app/billing에서 충전하세요. 예외: Retry-After 헤더가 있으면 자동 충전이 진행 중이라는 뜻입니다. 충전이 완료된 후 재시도하세요.
403permission_error — 키는 유효하지만 IP 허용 목록에 현재 IP가 포함되어 있지 않습니다.아니요 — 허용된 주소에서 호출하세요.
404model_not_found — 알 수 없거나 비활성화된 모델 ID입니다.아니요 — /v1/models를 확인하세요.
404missing_v1_prefix — api.kunavo.com에서 /v1가 없는 엔드포인트 경로를 사용했거나, 기본 호스트로 POST 요청을 보냈습니다.아니요 — 기본 URL을 https://api.kunavo.com/v1로 설정하세요.
404unknown_url — /v1 아래에 해당 경로의 엔드포인트가 없습니다. 메시지에 가장 가까운 경로가 표시됩니다.아니요 — 경로를 수정하세요.
408클라이언트 요청 시간 초과입니다.예. 단, 멱등성에 유의하세요.
422upstream_422 — 업스트림에서 입력을 거부했습니다(예: 지원하지 않는 크기).아니요 — 입력을 조정하세요.
429요청이 너무 많아 속도가 제한되었습니다. 동시 호출 수가 너무 많습니다.예 — 지수 백오프를 사용하세요.
500Kunavo 내부 오류입니다.예 — 짧은 백오프를 적용하세요.
502upstream_error — 업스트림 제공업체에서 오류가 발생했습니다.예 — 지수 백오프를 사용하세요.
504작업 시간이 초과되었습니다(이미지/동영상 생성 시간이 폴링 예산을 초과함).예. 다만 비용이 발생할 수 있습니다.
실패한 호출(4xx 및 5xx)에는 요금이 청구되지 않습니다. usage_logs의 비용 항목은 $0입니다. 예외: 장시간 실행되는 작업 API에서 504 시간 초과가 발생한 경우, 작업은 완료되었지만 결과를 전달하지 못했다면 업스트림 비용이 표시될 수 있습니다. 드문 경우입니다.

일반적인 오류 코드

authentication_error

  • Authorization: Bearer ... 헤더 설정을 잊었습니다.
  • /app/keys에서 API 키가 취소되었습니다.
  • 키의 접두사가 여전히 잘못되었습니다(sk-kn-로 시작해야 함).

insufficient_quota

  • 이 요청을 처리하기에 지갑 잔액이 부족합니다 → error.code는 insufficient_balance이며, 오류에는 지갑 보유액(balance_usd), 이 요청에서 예약하는 금액(needed_usd), 두 개의 링크가 포함됩니다. topup_url를 열면 충전 금액이 미리 선택된 결제 페이지가 표시되고, auto_recharge_url를 열면 자동 충전 설정이 표시됩니다. 링크를 여는 것만으로는 요금이 청구되지 않습니다.
  • 키별 월간 한도에 도달했습니다. 한도는 매월 1일(UTC)에 초기화됩니다. /app/keys에서 한도를 높이세요.
{
  "error": {
    "message": "Wallet balance is too low for this request. Top up at https://kunavo.com/app/billing — or turn on auto-recharge there, and a saved card refills the wallet before requests are refused.",
    "type": "insufficient_quota",
    "code": "insufficient_balance",
    "param": null,
    "balance_usd": 0.0142,
    "needed_usd": 0.0381,
    "topup_url": "https://kunavo.com/app/billing?topup=20",
    "auto_recharge_url": "https://kunavo.com/app/billing?autorecharge=1&src=api_402"
  }
}

응답에 Retry-After 헤더가 없는 한 insufficient_balance에서는 재시도를 중단하세요. 이 헤더가 있으면 저장된 카드로 자동 충전이 진행 중이라는 뜻이며, 몇 초 후 같은 요청이 성공해야 합니다.

permission_error

  • 키에 IP 허용 목록이 설정되어 있지만, 호출이 목록에 없는 주소에서 들어왔습니다. 메시지에 확인된 주소가 표시됩니다. /app/keys에서 해당 주소(또는 CIDR 블록)를 추가하거나, 허용 목록을 완전히 삭제해 모든 주소를 허용하세요.
  • 에이전트를 새 호스트나 새 NAT 게이트웨이로 옮기거나, 다른 네트워크에 연결된 노트북에서 실행하면 해당 주소가 바뀝니다. 허용 목록이 없는 키는 이 사유로 거부되지 않습니다.

model_not_found

  • 슬러그의 철자가 잘못되었습니다. 표준 목록은 /models에서 확인하세요.
  • 모델이 현재 비활성화되어 있습니다(업스트림 장애 또는 가격 검토).

upstream_error

업스트림 모델 제공업체에서 오류를 반환했지만, 이를 더 구체적인 코드로 변환할 수 없음을 나타냅니다. 응답 본문에 원본 메시지가 포함됩니다. 일반적인 원인은 다음과 같습니다.

  • 제공업체 측 과부하입니다.
  • 콘텐츠 조정 정책에 의해 거부되었습니다(다른 프롬프트를 시도하세요).
  • 지역 또는 이용 가능 여부 제한입니다.

재시도 전략

가장 간단하고 안정적인 방법은 429 및 5xx에서만 지터를 적용한 지수 백오프를 사용하는 것입니다.

import time, random
from openai import OpenAI, RateLimitError, APIError

client = OpenAI(api_key=os.environ["KUNAVO_API_KEY"], base_url="https://api.kunavo.com/v1")

def call_with_retry(call, max_attempts=5):
    for attempt in range(max_attempts):
        try:
            return call()
        except RateLimitError:
            if attempt + 1 == max_attempts: raise
            # 429: exponential backoff with jitter
            time.sleep(min(2 ** attempt, 30) + random.random())
        except APIError as e:
            if e.status_code and 500 <= e.status_code < 600 and attempt + 1 < max_attempts:
                time.sleep(min(2 ** attempt, 30) + random.random())
            else:
                raise

result = call_with_retry(lambda: client.chat.completions.create(
    model="claude-haiku-4-5",
    messages=[{"role": "user", "content": "hi"}],
))
  • 시도당 대기 시간은 최대 30초, 전체 시도 횟수는 최대 5회로 제한하세요.
  • 408 및 429를 제외하고 4xx는 재시도하지 마세요. 재시도해도 시간만 낭비됩니다.
  • 이미지 생성과 동영상 생성은 멱등적이지 않습니다. 재시도는 새로운 생성이며, 성공하면 요금이 청구됩니다. 실패한 호출에는 요금이 청구되지 않았으므로 이를 재시도하는 것은 안전합니다. 동영상의 경우 POST /v1/videos는 Idempotency-Key 헤더를 지원하며, 같은 키로 다시 제출하면 첫 번째 작업이 반환됩니다.
  • 자체 코드에서 부수 효과가 있는 채팅 요청을 처리할 때는 애플리케이션 계층에서 멱등성 키를 사용해 중복을 제거하세요.

대시보드에서 디버깅하기

성공 여부와 관계없이 모든 API 호출을 /app/usage에서 확인할 수 있습니다. 행을 클릭하면 전체 요청/응답 상세 페이지가 열립니다.

  • 클라이언트에 반환된 HTTP 상태 코드입니다.
  • 해당하는 경우 업스트림 오류 코드입니다.
  • 지연 시간, 요청 IP, 사용자 에이전트입니다.
  • 상태별로 필터링하면 패턴을 파악하는 데 도움이 됩니다(예: 특정 모델에서 발생한 모든 422 오류).

인시던트 신고

정상 작동해야 하는 모델에서 5xx 오류가 계속 발생하면 다음 정보를 support@kunavo.com으로 이메일로 보내세요.

  • 모델 슬러그와 샘플 요청 본문(비밀 정보는 삭제하세요).
  • 오류가 발생한 시간대입니다.
  • 응답의 오류 code 및 message입니다.
  • 가능하다면 /app/usage/[id]의 사용 로그 링크를 보내주세요.

영업일 기준 1일 이내에 응답하며, 긴급하고 매출에 영향을 미치는 문제에는 더 빠르게 응답합니다.

다음 단계