- API 請求錯誤 — 同步 API 呼叫的 HTTP 回應(驗證、計費、請求格式錯誤、找不到資源)。見 API 請求錯誤。
- 預測失敗代碼 — 請求已被接受並排進佇列,但預測本身以
status: "failed"結束。失敗的內容由預測上的error物件描述,可從預測狀態端點取得,webhook 投遞與 result 端點也會帶上它。見預測失敗代碼。
預測失敗代碼
失敗的預測會攜帶一個error 物件:
失敗的預測不會計費;為該請求預留的點數會被釋放。
預測若沒有失敗,其
error 為 null。若您是在 2026 年 8 月 17 日之前完成整合,請見遷移說明。
錯誤會在哪裡出現
同一個error 物件會在每條通道上發布,您平常在哪裡看,就在哪裡讀得到它:
從 result 端點讀取失敗資訊
對一個已失敗的預測索取它的輸出,會得到400,並帶上造成這次失敗的那個錯誤,請求層級的 code 為 PREDICTION_FAILED:
error.code是PREDICTION_FAILED,屬於 API 請求錯誤,意思是「您索取輸出的那個預測並沒有產出輸出」;error.details才是預測自己的error物件 — 與/status對同一請求回報的內容完全一致,因此兩個端點不可能對失敗原因給出不同說法。請依error.details.reason與error.details.retryable分支。
error.message 會複述預測的 message,因此只讀最外層 message 的用戶端也能拿到有用的資訊。
兩個 timestamp,兩種含義。 最外層的 timestamp 是這個 HTTP 回應產生的時刻;error.details.timestamp 是預測失敗的時刻。若您隔了幾天才來取,兩者會相差好幾天。凡是要表達「失敗發生在何時」,請讀裡層那一個。
官方用戶端函式庫已經替您拆好:result() 拋出的錯誤,其 code、reason、retryable 就是預測自己的值,與 subscribe() 對同一次失敗拋出的完全一致。
仍在佇列中、仍在執行中,或已被取消的預測,回傳的仍是一直以來的那個通用 400。
判斷要不要重試
看retryable。它只回答一個問題 — 把一模一樣的請求再送一次,結果會不會不同 — 而且與 code 無關:同一個 code 這次失敗可以重試,換一次失敗可能就不行。
retryable 是選填欄位。缺席時,請回退到下表中依 code 而定的預設值。這正是這個欄位出現之前 Sunra 的行為,所以回退永遠是安全的,只是比較不精確。
code
reason
reason 指出 code 背後的具體原因。請把它用在指標統計、分流與技術支援診斷;重試決策請用 retryable。
目前公布的每個 reason 在下方都有獨立一節,錨點就是 reason 本身 — #input_fetch_failed、#moderation_blocked 等 — 因此錯誤報告可以直接連到它的含義。
input_validation_failed
code: invalid_input · retryable: false
請求沒有通過 Sunra 自己的 schema 或參數驗證。message 會點名出問題的欄位。
該怎麼辦: 修正被點名的欄位。原封不動重送只會再失敗一次。
provider_rejected_input
code: invalid_input · retryable: false
模型供應商拒絕了一個或多個輸入參數。供應商有告訴我們是哪一個時,message 會轉述;有些供應商只回報輸入不可接受,不說是哪一項,這種情況我們就照實這麼說,不做猜測。
該怎麼辦: 對照該模型的 schema 檢查參數 — 取值超出範圍、組合不受支援、長寬比或長度模型不接受等。
input_fetch_failed
code: invalid_input · retryable: false 或 true
以 URL 提供的輸入檔案抓取失敗。這是唯一一個 retryable 會真正變動的 reason,所以請讀欄位,不要臆測:
false— 對方主機拒絕了我們:4xx、不允許抓取的位址、重新導向,或檔案大小超限;true— 對方主機一時連不上:5xx、逾時,或 DNS 解析失敗。
message 會回顯您提交的 URL,方便您判斷是哪個輸入出了問題 — 但會去掉 query string,因此 presigned URL 中攜帶的憑證絕不會被回顯給您:
retryable 為 false 時,請確認該 URL 是否可從公開網路存取、presigned 連結是否已過期;為 true 時直接重試。
moderation_blocked
code: unsafe_content · retryable: false
被模型供應商的內容安全系統攔下 — 可能攔的是送進去的 prompt 與素材,也可能是產生回來的輸出。
該怎麼辦: 修改 prompt 或素材。相同內容重送必定會再被攔一次。
provider_rate_limited
code: service_provider_error · retryable: true
模型供應商正在限流。
該怎麼辦: 帶退避重試,或改走其他模型。
provider_unavailable
code: service_provider_error · retryable: true
模型供應商未能完成這次請求。
該怎麼辦: 稍後重試,或改走其他模型。
provider_timeout
code: task_timeout · retryable: true
預測未在允許時間內完成。
該怎麼辦: 重試 — 挑負載較低的時段,或把請求做小(更短長度、更低解析度),成功率會更高。
provider_account_error
code: internal_server_error · retryable: false
我方在該模型供應商的帳號有問題 — 帳務、憑證,或永久性配額。這是我們的問題,不是您輸入的問題。
該怎麼辦: 您這邊不用做什麼;重試無濟於事,我們已自動收到告警。若現在就需要這部分產能,請改走其他模型。
endpoint_misconfigured
code: internal_server_error · retryable: false
這個模型端點在我方設定有誤。
該怎麼辦: 您這邊不用做什麼;重試無濟於事,我們已自動收到告警。若情況緊急,請帶著 request_id 聯絡技術支援。
queue_enqueue_failed
code: internal_server_error · retryable: true
預測未能排進佇列。
該怎麼辦: 重新提交該請求。
reaped_stalled
code: internal_server_error · retryable: true
預測卡住後被終止。
該怎麼辦: 重新提交該請求。
未知值
code 與 reason 都是開放集合。 隨著我們歸類更多失敗,新值會直接加入,不會另行發布 breaking change 公告。您的整合在遇到不認得的值時,不得崩潰、不得丟掉這個錯誤,也不得拒收整個負載。
- 不認得的
reason— 當成reason缺席處理,改用retryable(或依code而定的預設值)決策。請把原始值記進日誌:這是技術支援定位問題最快的線索。 - 不認得的
code— 當成internal_server_error處理。有一個哨兵值值得記住名字:unknown_error_code,代表預測確實失敗了,但 Sunra 無法為它還原出任何分類。
遷移說明:沒有錯誤時 error 為 null
2026 年 8 月 17 日起生效。error 物件在每條通道上只有一種表示形式。它們之間的三處差異已經消失:
- 預測沒有失敗時,
error為null。 過去GET /v1/predictions/{prediction_id}對每一個已成功、仍在佇列中或已取消的預測,回答的都是一個空物件 —"error": {}。現在它回答"error": null,佇列狀態端點一直以來就是這麼做的。若您的程式是在判斷它是否為空(Object.keys(response.error).length === 0),請改成判斷是否為 null(response.error === null)。 - 失敗必定攜帶非空的
code與message。 若某次失敗記錄下來的內容我們無法歸類,您現在拿到的是unknown_error_code這個哨兵值與一則通用訊息,而不是一個缺席、為空或根本不是字串的欄位。 - 以純文字記錄的失敗,會以文字送到您手上。 2026 年 4 月有少數幾個預測把自己的錯誤存成了一個裸字串。過去
GET /v1/predictions/{prediction_id}會把它丟掉,佇列狀態端點則會用哨兵訊息取代它;現在兩者都會把它放在code: "unknown_error_code"之下、以message發布。
error 本來就在上述每一個回應裡,變的只是它的值。Webhook 投遞完全沒有變動 — 其他通道正是向它的形狀收斂 — succeeded 投遞中的 error 依然是缺席,而不是送出 null。
相容期間。 沒有雙寫過渡期;API 自該日起就不再產生 "error": {}。若您要重播或重新處理在那之前擷取的負載,請在這些存檔資料自然淘汰之前,把 null 與 {} 視為同一回事。
即將到來的變化:部分失敗會拿到更精確的 code
今天有相當大一部分失敗被回報為 service_provider_error,其中不少既不是暫時性的,也不是供應商的錯。隨著我們逐個供應商完成歸類,這些失敗會轉到真正描述它們的 code:
- 供應商確定性地拒絕您的輸入 →
invalid_input(原為service_provider_error); - Sunra 這一側的問題,例如端點設定錯誤或我方供應商帳號問題 →
internal_server_error(原為service_provider_error); - 抓取不到的輸入檔案 →
invalid_input(原為internal_server_error)。
code 值 — 上表五個值仍然是已歸類 code 的全集。變的是某次失敗會落到其中哪一個,而且是按供應商逐批、漸進發生的。如果您的程式正在依 code 分支,現在正是把這段邏輯搬到 retryable 與 reason 上的好時機:它們直接描述失敗本身,不受這次重新歸類影響。