PopNowAPI 문서
레퍼런스
본문

오류

모든 업무 코드의 의미와 해결 방법, 그리고 재시도할 가치가 있는 오류.

호출이 실패하면 응답은 문제의 종류를 나타내는 숫자(code)와 사람이 읽을 문장(msg)을 돌려줍니다. 분기는 숫자로 하고, 문장은 화면에 보여 주거나 로그에 남기세요.

응답 형식

{ "code": 40201, "msg": "Insufficient balance", "request_id": "req_…" }
  • code는 업무 코드입니다. 200이 성공이고 나머지는 아래 표에 있습니다.
  • 실패하면 data 필드가 없습니다. 일부 에셋 라이브러리 오류만 data.reason을 추가합니다.
  • HTTP 상태도 맞게 설정됩니다(40201이면 HTTP 402). 둘 중 하나로만 분기하고 섞지 마세요. 더 구체적인 code를 권장합니다.
  • request_id는 X-Request-Id 헤더에도 들어 있습니다. 고객 지원에 문의할 때 함께 보내 주세요.

응답이 아예 JSON이 아니라면(중간 네트워크가 돌려준 HTML이나 텍스트 페이지 등) HTTP 상태로 처리하고 본문 앞부분을 로그에 남기세요.

오류 메시지 언어

msg와 실패한 작업의 errorMessage는 기본이 영어입니다. Accept-Language에 en, ja, ko, de, fr, es, pt-BR, ru, it, pl 중 하나를 보내거나 콘솔에서 API 오류 언어를 설정하면 그 언어로 받습니다. 다른 언어는 영어로 돌아옵니다. 오류 응답에는 Content-Language가 붙습니다. 코드는 언어에 따라 바뀌지 않습니다. msg를 파싱하면 안 되는 또 하나의 이유입니다.

모델이 구체적인 실패 이유(예: 읽을 수 없는 참조 이미지)를 알려 주면, errorMessage는 그 이유를 내부 정보만 지운 영어 원문으로 전달합니다.

일반 코드

codeHTTP의미재시도?
200200 / 202성공—
400400요청이나 input이 잘못됨. msg가 문제를 알려 줍니다아니요, 고친 뒤에
40003400업로드한 파일이 업로드 티켓과 다름(크기, 형식, 내용)아니요, 티켓을 새로 받아 다시 업로드
40004400요청은 맞지만 지금 이 모델이 이 설정 조합을 처리할 수 없음아니요, msg가 가리키는 설정을 바꾸세요
401401키가 없거나, 알 수 없거나, 폐기됨(자세히)아니요
403403허용되지 않음(권한 참고)아니요
404404존재하지 않거나 다른 키의 것아니요
409409현재 상태와 충돌(재시도 기준)경우에 따라
40901409견적이 만료됐거나 가격이 바뀜다시 견적
413413요청 본문이 너무 큼아니요, 인라인 대신 업로드
429429요청이 너무 많음예, Retry-After 이후에
500500저희 쪽 오류예, 백오프하며
503503보조 서비스가 잠시 사용 불가예, Retry-After 이후에

잔액과 한도

codeHTTP의미해결 방법
40201402이 작업에 잡아 둘 크레딧이 부족함크레딧을 구매한 뒤 다시 보내기
40202402키의 지출 한도에 도달API 콘솔에서 한도를 올리거나 초기화를 기다리기

권한

codeHTTP의미해결 방법
40301403이 키로는 이 모델을 호출할 수 없음키의 허용 모델에 추가
40302403요청 주소가 키의 IP 허용 목록에 없음주소를 추가하거나 제한을 해제
40303403이 지역에서는 서비스를 제공하지 않음우회할 수 없습니다
40310403계정 이메일이 아직 인증되지 않음가입 메일의 링크를 여세요. 인증되면 바로 키가 작동합니다

유효한 키인데 일반 403이 오면 계정이 지금 API를 쓸 수 없는 상태입니다. request_id와 함께 고객 지원에 문의하세요.

모델 사용 가능 여부

codeHTTP의미재시도?
50301503이 모델이 지금 작업을 받을 수 없음예, 나중에 또는 다른 모델로
40004400모델은 정상이지만 이 설정으로는 안 됨아니요, 설정을 바꾸세요

둘 다 작업을 만들지 않고 크레딧도 잡아 두지 않습니다.

작업 실패 코드

접수된 뒤 실패한 작업은 state: "failed"가 되고 errorCode에 아래 중 하나가 들어갑니다. 목록은 닫혀 있으니 다른 값이 오면 upstream_failed로 처리하세요.

errorCode의미재시도?
invalid_request모델이 파라미터를 받아들이지 않음아니요, 고친 뒤에
unsupported_combination지금은 이 설정 조합을 지원하지 않음아니요, 설정을 바꾸세요
content_rejected모델이 이 내용을 거절함아니요, 프롬프트나 참조 자료를 바꾸세요
invalid_asset참조 파일을 읽을 수 없거나 더 이상 없음다시 업로드하고 새 작업을 만드세요
rate_limited생성 서비스가 바빴음예, 백오프하며
upstream_unavailable생성이 잠시 불가능함예, 잠시 후에
generation_failed생성은 돌았지만 결과가 없음경우에 따라. 같은 입력은 같은 식으로 실패하기 쉽습니다
timeout시간 초과경우에 따라. 더 짧게 또는 낮은 해상도로
upstream_failed그 밖의 모든 경우예, 백오프하며

실패한 작업은 잡아 둔 크레딧을 돌려주므로 비용이 들지 않습니다(일부 모델은 콘텐츠 거절에도 과금하며 해당 모델 페이지에 적어 둡니다). errorMessage는 이유를 문장으로 알려 줄 뿐이니 분기는 errorCode로만 하세요.

409를 재시도해야 할 때

상황재시도?
같은 Idempotency-Key의 요청 두 개가 동시에 도착예, 잠시 뒤 같은 키로
그 Idempotency-Key가 다른 요청이나 다른 키에서 이미 쓰임아니요
업로드나 결과물이 아직 처리 중예, 몇 초 뒤에
아직 끝나지 않은 작업에 jobs/retry예, 종료 상태가 된 뒤에
성공한 작업에 jobs/retry아니요, 새 작업을 만드세요
업로드 티켓이나 업로드 파일이 만료됨아니요, 다시 업로드

재시도 코드 작성법

다시 보냈을 때 성공할 수 있는 것만 재시도하고, Retry-After가 있으면 따르고 없으면 지수 백오프로 기다립니다.

JavaScript
const RETRYABLE = new Set([429, 500, 503, 50301]);

async function call(path, init, attempts = 4) {
  for (let i = 0; i < attempts; i++) {
    const res = await fetch(`https://api.popnow.ai/api/v1${path}`, init);
    if (!res.headers.get('content-type')?.includes('json')) {
      throw new Error(`HTTP ${res.status}: ${(await res.text()).slice(0, 200)}`);
    }
    const body = await res.json();
    if (body.code === 200) return body.data;
    if (!RETRYABLE.has(body.code)) throw new Error(`${body.code} ${body.msg} (${body.request_id})`);
    const wait = Number(res.headers.get('retry-after')) * 1000 || 2 ** i * 1000 + Math.random() * 500;
    await new Promise((r) => setTimeout(r, wait));
  }
  throw new Error('out of retries');
}
Python
import random, time, requests

RETRYABLE = {429, 500, 503, 50301}

def call(method, path, attempts=4, **kwargs):
    for i in range(attempts):
        res = requests.request(method, f"https://api.popnow.ai/api/v1{path}", timeout=60, **kwargs)
        try:
            body = res.json()
        except ValueError:
            raise RuntimeError(f"HTTP {res.status_code}: {res.text[:200]}")
        if body["code"] == 200:
            return body["data"]
        if body["code"] not in RETRYABLE:
            raise RuntimeError(f'{body["code"]} {body["msg"]} ({body.get("request_id")})')
        retry_after = res.headers.get("retry-after")
        time.sleep(float(retry_after) if retry_after else 2**i + random.random() / 2)
    raise RuntimeError("out of retries")

createTask를 재시도할 때는 항상 같은 Idempotency-Key를 보내세요. 실제로는 성공한 요청이 두 번 실행되고 두 번 과금되는 일을 막아 줍니다.

문제 추적

  1. request_id와 code를 적어 둡니다.
  2. API 콘솔의 로그에서 작업 ID나 request_id로 작업을 찾습니다.
  3. 그래도 해결되지 않으면 request_id, 시각(UTC), code를 함께 보내 고객 지원에 문의하세요. API 키는 절대 보내지 마세요.

이 페이지에서