{"record":{"id":"6621f87aed18bd5c","repo":"CherryHQ/cherry-studio","slug":"task-polling-timeout-6621f8","errorCode":null,"errorMessage":"Task polling timeout","messagePattern":"Task polling timeout","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/main/ai/provider/custom/modelscope/modelscopeTransport.ts","lineNumber":187,"sourceCode":"        }\n\n        transientRetries++\n        if (transientRetries >= maxTransientRetries) {\n          throw error instanceof Error ? error : new Error(String(error))\n        }\n        const elapsedTime = Date.now() - startTime\n        const pollDelay = interval ?? (elapsedTime < 60000 ? 3000 : 10000)\n        await waitWithSignal(pollDelay, signal)\n        continue\n      }\n\n      const elapsedTime = Date.now() - startTime\n      const pollDelay = interval ?? (elapsedTime < 60000 ? 3000 : 10000)\n      await waitWithSignal(pollDelay, signal)\n      attempts++\n    }\n\n    throw new Error('Task polling timeout')\n  }\n\n  private async request<T>(\n    path: string,\n    method: 'POST' | 'GET',\n    body: Record<string, unknown> | undefined,\n    options: { timeout?: number; signal?: AbortSignal; extraHeaders?: Record<string, string> }\n  ): Promise<T> {\n    const timeout = options.timeout ?? DEFAULT_TIMEOUT\n    const externalSignal = options.signal\n    const controller = new AbortController()\n    let externallyAborted = false\n\n    const timeoutId = setTimeout(() => controller.abort(), timeout)\n    const onExternalAbort = () => {\n      externallyAborted = true\n      controller.abort()\n    }","sourceCodeStart":169,"sourceCodeEnd":205,"githubUrl":"https://github.com/CherryHQ/cherry-studio/blob/726446b54cd69ffe51a276638672f6d95ca0768c/src/main/ai/provider/custom/modelscope/modelscopeTransport.ts#L169-L205","documentation":"Thrown by `ModelscopeTransport.pollTaskResult` after exceeding `maxAttempts` (default 120) polls without the task reaching `SUCCEED`. The poll interval scales from 3s (first 60s) to 10s, giving a default budget of roughly 15–20 minutes. This is budget exhaustion, not a vendor-side failure.","triggerScenarios":"A ModelScope async image task that never completes within the polling window: a slow model under load, a stuck PENDING/RUNNING task, or repeated transient poll failures consuming retries without progress.","commonSituations":"Heavy model under vendor load; network latency inflating poll round-trips; free-tier queuing behind other tasks; repeated 5xx/429 polls using up transient retries.","solutions":["Increase `maxAttempts` / `interval` in the poll options to extend the budget for slow models.","Check network connectivity to `api-inference.modelscope.cn` and retry.","If tasks are consistently stuck at PENDING, verify the model is available and the account is not rate-limited."],"exampleFix":null,"handlingStrategy":"retry","validationCode":"const POLL_OPTIONS = { maxAttempts: 180, interval: 5000 } // extend budget for slow models","typeGuard":null,"tryCatchPattern":"try {\n  urls = await transport.poll(taskId, { ...opts, maxAttempts: 180 })\n} catch (e) {\n  if (e instanceof Error && e.message === 'Task polling timeout') {\n    // resubmit or surface a 'generation is taking too long' message\n  }\n  throw e\n}","preventionTips":["Size maxAttempts/interval to the slowest supported model","Treat timeout as retriable — resubmit rather than hard-failing","Monitor network latency to api-inference.modelscope.cn"],"tags":["timeout","polling","modelscope","async"],"backgroundTag":null,"analyzedSha":"726446b54cd69ffe51a276638672f6d95ca0768c","analyzedAt":"2026-08-12T17:30:37.448Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}