튜토리얼
HiAPI 작업이 TASK_FAILED를 반환함: 원인과 수정 방법
최종 상태 작업 반환을 이해하고, 각종 원인을 하나씩 수정하며, 진짜 실패와 4xx, 타임아웃을 구분합니다.
HiAPI 작업 API에 비동기 작업을 제출하면, 제출 성공 시 HTTP 200과 taskId가 반환됩니다. 작업은 이후 백그라운드에서 실행되며, 폴링할 때 최종 상태 fail로 끝날 수 있습니다. 이때 폴링 반환은 대략 다음과 같습니다——HTTP 호출 자체는 여전히 200이라는 점에 주목하세요:
{
"code": 200,
"data": {
"taskId": "tk-hiapi-01M4RK...",
"model": "seedream-5.0-lite/image-to-image",
"status": "fail",
"error": { "code": "TASK_FAILED", "message": "task failed" },
"created": 1791827316,
"completed": 1791827352,
"storage": "temp"
},
"message": "success"
}
이것이 흔히 말하는 「TASK_FAILED 오류」입니다: 요청은 접수되었고, 작업은 실행되었으며, 마지막에 성공하지 못한 것입니다. 이것은 HTTP 4xx 오류가 아니며, 타임아웃도 아닙니다. 이 글에서는 이 반환을 읽는 방법과 각종 원인을 하나씩 수정하는 방법을 알려드립니다.
먼저 알아둘 것: TASK_FAILED는 HTTP 상태 코드가 아닙니다
가장 이해해야 할 점:
- 폴링 호출의 HTTP 상태 코드는
200이고, 반환 본문에는 심지어"message": "success"라고 적혀 있습니다——이는 API 호출이 성공했을 뿐, 작업이 성공했음을 의미하지 않습니다. "status": "fail"(data안에 있음)이 작업 실패를 판단하는 근거입니다. 완료된 작업의 경우data.status는"success"또는"fail"뿐입니다."TASK_FAILED"는 status가 아니라data.error.code의 값입니다. 일부 실패는 더 구체적인 code와 더 유용한 message를 동반합니다(아래 참조).
따라서 항상 GET /v1/tasks/{taskId}를 폴링하고, data.status를 분기 기준으로 삼아야 하며, 절대 HTTP 상태 코드만 보고 성패를 판단해서는 안 됩니다.
작업 상세에서 원인 파악하기
최종 상태 반환을 받으면 이 순서대로 data 필드를 읽습니다:
- 먼저
data.status를 봅니다——"fail"이어야 작업 실패입니다. - 다음으로
data.error.code를 읽습니다——기계가 판별할 수 있는 오류 범주입니다(예:TASK_FAILED,INVALID_REQUEST,CONTENT_POLICY_VIOLATION). - 마지막으로
data.error.message를 읽습니다——사람이 보는 설명이며, 보통 원인을 직접 짚어 줍니다(예: 특정 입력 URL을 가져올 수 없음).
error.code는 이 실패가 「재시도로 해결될 수 있는지」를 대체로 결정합니다: 일반화된 TASK_FAILED(message가 대개 "task failed")는 흔히 일시적 문제이므로 재시도할 수 있습니다; 명확한 code가 있는 경우(예: INVALID_REQUEST, CONTENT_POLICY_VIOLATION)는 확정적 실패에 속하므로 입력을 바꾸지 않고 몇 번을 재시도해도 결과는 같습니다.
흔한 최종 상태 fail 원인
대략 발생 빈도가 높은 순서대로 나열합니다.
1. 입력 이미지 / 비디오 URL에 접근할 수 없거나 공용 네트워크가 아님
이미지-투-이미지, 이미지/비디오-투-비디오 작업에서 가장 흔한 원인입니다. input이 플랫폼이 가져올 수 없는 URL을 참조하면, 작업은 접수되지만 실행 시 실패합니다. 실제 최종 상태 반환:
"error": {
"code": "INVALID_REQUEST",
"message": "The image URL could not be downloaded. Please provide a reachable public HTTP(S) URL and try again."
}
여기서 message는 이미 명확히 설명하고 있습니다. 다른 모델들은 같은 근본 원인을 일반화된 TASK_FAILED / "task failed"로 노출하기도 합니다.
수정: 입력을 공용 네트워크에서 접근 가능한 HTTPS URL로 호스팅하고, 제출 전에 먼저 검증하세요:
curl -I "https://your-host.example.com/input.png"
# 반드시 200을 반환하고 직접 링크 미디어 content-type(image/* 또는 video/*)이어야 함
# 401/403/404가 아니어야 하며, HTML 페이지도 아니어야 함
만료된 사전 서명 URL, localhost / 내부 네트워크 주소, 로그인해야 열리는 링크가 가장 흔한 함정입니다. 이는 확정적 실패에 속합니다——URL을 고치지 않으면 재시도는 작업을 한 번 더 헛되이 실행할 뿐입니다.
2. 일시적 또는 업스트림 생성 실패
때때로 형식이 완전히 올바른 작업이 일반화된 error.code: "TASK_FAILED", message: "task failed"로 실패하며 더 이상의 세부 정보가 없을 수 있습니다. 이런 경우 대부분 일시적 변동입니다.
수정: 한두 번 재시도하세요. 같은 입력으로 반복 실패하면 입력을 간소화(prompt 단축, 선택 필드 제거)한 뒤 다시 실행하여 트리거 범위를 좁히세요.
3. 콘텐츠가 안전 정책에 의해 차단됨
prompt나 입력 이미지가 플랫폼의 콘텐츠 안전 정책에 걸리면, 작업은 확정적인 정책성 오류로 끝나며 data.error.code는 CONTENT_POLICY_VIOLATION입니다.
수정: 이는 영구적 실패이며 재시도는 무효입니다. prompt와 입력 소재를 조정하고 위반 콘텐츠를 제거한 뒤 다시 제출하세요.
4. 모델이 런타임에야 거부하는 특정 매개변수
대부분의 잘못된 매개변수는 제출 시 HTTP 400으로 차단됩니다(taskId를 아예 받을 수 없음)——다음 절을 참조하세요. 간혹 그 자체로는 합법적이지만 조합상 모델이 지원하지 않는 옵션이 작업 실행 시에만 거부되어 data.status: "fail"로 떨어집니다. error.message가 어느 옵션인지 짚어 줍니다.
수정: data.error.message를 읽고, 모델 페이지에서 해당 모델이 지원하는 입력을 확인한 뒤(예: GPT Image 2 모델 페이지), 지목된 필드를 삭제하거나 수정하세요.
TASK_FAILED, 4xx, 타임아웃 구분 방법
세 가지 전혀 다른 상황이 모두 두루뭉술하게 「실패했다」고 표현되지만, 수정 방법은 다릅니다:
| 보이는 것 | 의미 | 수정 위치 |
|---|---|---|
POST가 비 2xx(400/401/402/429)를 반환하고 taskId가 없음 |
요청이 거부되어 작업이 아예 실행되지 않음 | 요청 / key / 잔액 수정(아래 링크 참조) |
POST가 200 + taskId를 반환하고, 폴링 시 data.status: "fail" 표시 |
TASK_FAILED——작업이 실행되었고 실패함 | data.error.message 읽기(이 글) |
POST가 200 + taskId를 반환하고, 폴링이 마감 시간을 넘겨도 비최종 상태(예: handling)에 머묾 |
타임아웃, 실패가 아님 | 계속 폴링 / 타임아웃 늘리기 / 재시도 |
taskId를 아예 받지 못했다면 TASK_FAILED가 아니라 요청 오류입니다:
HTTP 400매개변수 잘못됨, 누락 또는 미지원 → HiAPI 400 매개변수 오류 수정HTTP 401API key 무효 → API Key 무효 오류- 잔액 부족(생성 시점에 거부되므로 실패할 작업이 없음) → HiAPI 402 잔액 부족 수정
- 알 수 없거나 게시되지 않은 모델 id(
MODEL_UNAVAILABLE) → 「모델 없음 / 사용 불가」 - 작업이 끝내 최종 상태에 도달하지 못함 → HiAPI 작업 타임아웃과 504 오류
인증 실패는 요청 계층에서 거부되며, 반환은 HTTP 401 + {"error":{"code":"permission_denied","type":"hiapi_error","request_id":"..."}}이고, 작업이 생성되지 않으므로 당연히 TASK_FAILED일 수 없습니다.
수정 체크리스트
- 작업을 폴링하고, POST만 믿지 마세요. 제출은 작업이 대기열에 들어갔다는 것만 알려 줍니다.
GET /v1/tasks/{taskId}를 호출하고data.status를 보세요. - 진짜 실패인지 확인:
data.status == "fail"(HTTP 코드는 여전히200). data.error.code와data.error.message를 읽으세요. message가 최우선 신호입니다.- 입력 URL이 언급되면: URL을 공용 네트워크 접근 가능하게 바꾸고
curl -I로 검증하세요(200 + 직접 링크 미디어 content-type). - message가 일반화된 경우(
"task failed"): 일시적 문제로 보고 재시도하고, 계속 반복 실패하면 입력을 간소화하세요. CONTENT_POLICY_VIOLATION같은 확정적 오류라면: 영구적 실패이므로 자동 재시도하지 마세요——입력을 바꿔야 효과가 있습니다.- 모델 id가 현재
GET /v1/models에 있고 보낸 것과 완전히 일치하는지 확인하세요. 알 수 없는 id는 최종 상태 fail이 아니라 제출 시400 MODEL_UNAVAILABLE로 실패합니다. taskId가 전혀 없나요? 그렇다면 TASK_FAILED가 아닙니다——위의 해당 요청 오류 가이드로 가세요.
최소 검증 예시
특정 작업을 조사하기 전에, 깨끗한 요청 한 번으로 key와 연결성을 확인하세요. 통합 작업 API POST https://api.hiapi.ai/v1/tasks를 호출하며, 모델 id는 베어 id(endpoint 접미사 없음)를 사용합니다:
# 1) 제출——예상 HTTP 200 + taskId 하나
curl -s https://api.hiapi.ai/v1/tasks \
-H "Authorization: Bearer sk-YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{"model":"gpt-image-2","input":{"prompt":"a red bicycle on a white background","aspect_ratio":"1:1"}}'
# -> {"code":200,"data":{"taskId":"tk-hiapi-..."},"message":"success"}
# 2) 폴링——받은 taskId로 교체
curl -s https://api.hiapi.ai/v1/tasks/tk-hiapi-xxxxxxxx \
-H "Authorization: Bearer sk-YOUR_KEY"
# -> 실행 중 data.status는 "handling", 이후 "success" 또는 "fail"로 변경
1단계에서 200과 taskId가 반환되면 key와 API가 모두 정상이며, 어떤 실패든 접속 문제가 아니라 개별 작업의 문제입니다. 1단계에서 401이 반환되면 key가 잘못된 것이므로 HiAPI 콘솔에서 key를 관리하세요. 참고: 이 예시는 실제 생성을 한 번 제출하므로 비용이 발생합니다.
과금에 대하여: 실패할 운명의 작업에 반복 결제하지 마세요
실패한 작업의 과금 여부, 그리고 사전 차감과 환불이 어떻게 처리되는지는 HiAPI 실패 요청도 과금되나요?를 참조하세요. 두 가지 요점:
- 확정적 실패를 무작정 자동 재시도하지 마세요.
CONTENT_POLICY_VIOLATION, URL 접근 불가 같은 경우 매 재시도가 새 작업이고 과금될 수 있습니다. 먼저 입력을 바꾸고, 재시도 로직이 헛돌며 돈을 태우지 않게 하세요. - 제출 전에
curl -I로 입력 URL을 검증하세요. HEAD 검사 한 번은 무료이지만, 깨진 링크 때문에 실패할 운명의 작업은 비용이 발생할 수 있습니다.
FAQ
TASK_FAILED는 HTTP 상태 코드인가요?
아닙니다. HTTP 호출은 200을 반환합니다. TASK_FAILED는 최종 상태 반환에서 data.error.code의 값이며, 이 반환의 data.status는 "fail"입니다.
data.status는 "fail"인데 저는 "TASK_FAILED"를 찾고 있습니다——어느 것을 봐야 하나요?
각각 위치가 다릅니다. 완료된 작업의 data.status는 항상 "success" 또는 "fail"입니다; "TASK_FAILED"는 일반화된 data.error.code이며, 실패한 작업은 더 구체적인 code(예: INVALID_REQUEST, CONTENT_POLICY_VIOLATION)와 실행 가능한 message를 동반할 수도 있습니다.
어떤 TASK_FAILED는 재시도할 수 있고 어떤 것은 안 되나요?
일반화된 "task failed"(추가 세부 정보 없음)는 대개 일시적 문제이므로 한두 번 재시도할 수 있습니다; 명확한 code가 있는 확정적 실패(잘못된 URL → INVALID_REQUEST, 콘텐츠 위반 → CONTENT_POLICY_VIOLATION, 모델이 거부한 매개변수)는 재시도가 무효이며 입력을 바꿔야 합니다.
제 작업이 계속 handling에 머물며 실패하지도 성공하지도 않습니다.
그것은 타임아웃이며 실패가 아닙니다. 계속 폴링하거나 클라이언트 타임아웃을 늘리세요; HiAPI 작업 타임아웃과 504 오류를 참조하세요.
taskId 대신 400 / 401 / 402를 받았습니다.
그것들은 요청이 거부된 것입니다——작업이 생성되지 않았으므로 「실패」도 없습니다. 위에 링크된 가이드로 요청, key 또는 잔액을 수정하세요.
실패한 작업도 과금되나요? HiAPI 실패 요청도 과금되나요?에서 실패 시 사전 차감과 환불이 어떻게 처리되는지 확인하세요.
잘못된 입력 URL인지 어떻게 확인하나요?
data.error.message를 읽으세요. URL 문제는 보통 이미지나 비디오를 다운로드할 수 없다고 알려 줍니다; curl -I로 링크가 200을 반환하고 직접 링크 미디어 파일인지 검증하세요.
관련 글
모든 아티클 보기 →-
튜토리얼
HiAPI API로 hailuo-2.3-fast/image-to-video 호출하는 방법: curl과 Python 실전
빠르고 저렴한 이미지-투-비디오 등급의 첫 실행 요청 — 모델 ID부터 MP4 다운로드까지
-
튜토리얼
HiAPI API로 hailuo-2.3/text-to-video를 호출하는 방법: curl, Python 및 실행 가능한 요청 예시
-
튜토리얼
HiAPI에서 Kandinsky 6.0 Pro 텍스트-투-비디오 사용하기: curl 및 Python 튜토리얼
요청 우선 실전 데모: 프롬프트에서 비디오 클립까지의 호출 구성, 요청 제출, 완료 상태 폴링 및 결과 다운로드