{"record":{"id":"ff84ef119d728fa6","repo":"decolua/9router","slug":"runway-polling-timeout","errorCode":null,"errorMessage":"Runway polling timeout","messagePattern":"Runway polling timeout","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"open-sse/handlers/imageProviders/runwayml.js","lineNumber":42,"sourceCode":"    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":24,"sourceCodeEnd":49,"githubUrl":"https://github.com/decolua/9router/blob/90b52e06ffd666b7929554211474d01588f6b1f8/open-sse/handlers/imageProviders/runwayml.js#L24-L49","documentation":"The Runway generation task did not reach SUCCEEDED (or FAILED/CANCELLED) within POLL_TIMEOUT_MS, so parseResponse aborts polling and throws. Runway image/video generation is asynchronous: the code sleeps POLL_INTERVAL_MS between status checks and gives up once the deadline passes, even though the task may still be running upstream.","triggerScenarios":"parseResponse's `while (Date.now() < deadline)` loop expires — the task stays in RUNNING/QUEUED/PENDING for longer than POLL_TIMEOUT_MS while polling every POLL_INTERVAL_MS.","commonSituations":"Long video generations (image_to_video, 5s clips) or queues under heavy load exceeding the polling window; task stuck forever due to a Runway-side stall; POLL_TIMEOUT_MS configured too short for the chosen model; clock skew is irrelevant here but very slow networks add per-poll latency, effectively shrinking the window.","solutions":["Increase POLL_TIMEOUT_MS in open-sse/handlers/imageProviders/_base.js to cover the slowest model you use (video generation can take several minutes)","Fetch `${BASE_URL}/tasks/{id}` manually with the Bearer token to check the task's current status — if still running, the timeout was simply too short","Reduce POLL_INTERVAL_MS slightly to catch terminal transitions sooner (avoid hammering the API; keep a few seconds minimum)","Resubmit the generation; if tasks routinely time out on one model, switch to a faster image model (gen4_image)"],"exampleFix":"// before (open-sse/handlers/imageProviders/_base.js)\nexport const POLL_TIMEOUT_MS = 60_000;\n// after — allow up to 5 minutes for slow video tasks\nexport const POLL_TIMEOUT_MS = 300_000;","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  const result = await runwayImageCall(params);\n} catch (err) {\n  if (err.message === \"Runway polling timeout\") {\n    // task may still be running upstream — poll /tasks/{id} manually with backoff\n    // before resubmitting, to avoid duplicate generations\n  } else {\n    throw err;\n  }\n}","preventionTips":["Size POLL_TIMEOUT_MS to your slowest model (video tasks need minutes, not seconds)","For video generations prefer longer timeouts; only image models fit tight windows","On timeout, reconcile against the task endpoint instead of immediately resubmitting"],"tags":["runway","timeout","async-polling","image-generation"],"backgroundTag":"polling-timeout","analyzedSha":"90b52e06ffd666b7929554211474d01588f6b1f8","analyzedAt":"2026-08-30T21:05:45.952Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}