{"record":{"id":"b93129721c6d1717","repo":"decolua/9router","slug":"runway-task-failed","errorCode":null,"errorMessage":"Runway task failed","messagePattern":"Runway task failed","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"open-sse/handlers/imageProviders/runwayml.js","lineNumber":40,"sourceCode":"    const isVideo = !model.includes(\"image\");\n    const ratio = sizeToAspectRatio(body.size);\n    if (isVideo) {\n      return { promptText: body.prompt, model, ratio, duration: 5, ...(body.image ? { promptImage: body.image } : {}) };\n    }\n    return { promptText: body.prompt, model, ratio, ...(body.image ? { referenceImages: [{ uri: body.image }] } : {}) };\n  },\n  async parseResponse(response, { headers }) {\n    const { id } = await response.json();\n    if (!id) throw new Error(\"Runway: no task id returned\");\n    const taskUrl = `${BASE_URL}/tasks/${id}`;\n    const deadline = Date.now() + POLL_TIMEOUT_MS;\n    while (Date.now() < deadline) {\n      await sleep(POLL_INTERVAL_MS);\n      const r = await fetch(taskUrl, { headers });\n      if (!r.ok) throw new Error(`Runway status ${r.status}`);\n      const s = await r.json();\n      if (s.status === \"SUCCEEDED\") return s;\n      if (s.status === \"FAILED\" || s.status === \"CANCELLED\") throw new Error(s.failure || \"Runway task failed\");\n    }\n    throw new Error(\"Runway polling timeout\");\n  },\n  normalize: (responseBody) => {\n    const outputs = Array.isArray(responseBody.output) ? responseBody.output : [];\n    return { created: nowSec(), data: outputs.map((url) => ({ url })) };\n  },\n};\n","sourceCodeStart":22,"sourceCodeEnd":49,"githubUrl":"https://github.com/decolua/9router/blob/90b52e06ffd666b7929554211474d01588f6b1f8/open-sse/handlers/imageProviders/runwayml.js#L22-L49","documentation":"While polling an async Runway image/video generation task, the task reached terminal status FAILED or CANCELLED and no upstream `failure` reason string was present in the status payload, so this generic message is thrown. It means Runway itself rejected or aborted the generation — the request reached Runway fine, but the work did not produce output.","triggerScenarios":"parseResponse's poll loop (`GET {BASE_URL}/tasks/{id}`) reads `s.status === \"FAILED\" || s.status === \"CANCELLED\"` and `s.failure` is undefined/null, so the fallback message is used instead of a specific reason.","commonSituations":"Content-policy rejection of the prompt or reference image; unsupported aspect-ratio/model/duration combination in the submitted task; account out of credits so Runway cancels the task; Runway returning a failure payload without the `failure` field; using image_to_video with an invalid promptImage URL.","solutions":["Log the full task status JSON (fetch `${BASE_URL}/tasks/{id}` manually with the same Bearer token) to see the real `failure`/`status` details Runway returned","Review the prompt and any reference image for content-policy or format issues (unsupported ratio, oversized image URL) and resubmit","Verify the Runway account has credits/quota and the API key is active for the model used (gen4_image or video model)","Retry the generation — transient infra failures on Runway's side can also mark a task CANCELLED"],"exampleFix":"// before — reason is lost when s.failure is absent\nif (s.status === \"FAILED\" || s.status === \"CANCELLED\") throw new Error(s.failure || \"Runway task failed\");\n// after — preserve full upstream context\nif (s.status === \"FAILED\" || s.status === \"CANCELLED\") {\n  throw new Error(`Runway task ${s.status}: ${s.failure || JSON.stringify(s).slice(0, 500)}`);\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  const result = await runwayImageCall(params);\n} catch (err) {\n  if (err.message === \"Runway task failed\") {\n    // upstream rejected the generation — surface to user as a retryable/contract issue,\n    // inspect s.failure via task endpoint; do NOT retry with identical prompt blindly\n  } else {\n    throw err;\n  }\n}","preventionTips":["Pre-validate prompts and reference image URLs against Runway content/format rules before submitting","Confirm account credits before long batch generations","Log full task JSON from /tasks/{id} on failure to capture the real reason"],"tags":["runway","image-generation","async-polling","upstream-task-failure"],"backgroundTag":"upstream-task-failed","analyzedSha":"90b52e06ffd666b7929554211474d01588f6b1f8","analyzedAt":"2026-08-30T21:05:45.952Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}