CherryHQ/cherry-studio · error · Error

Task polling timeout

Error message

Task polling timeout

What it means

Thrown at the end of PpioTransport.pollTaskResult() when the loop has exhausted maxAttempts (default 120) without the task reaching TASK_STATUS_SUCCEED or TASK_STATUS_FAILED. It is a timeout on polling cadence, not on a single HTTP call — the task simply never settled.

Source

Thrown at src/main/ai/provider/custom/ppio/ppioTransport.ts:472

        transientRetries++

        if (transientRetries >= maxTransientRetries) {
          throw error instanceof Error ? error : new Error(String(error))
        }

        const elapsedTime = Date.now() - startTime
        const pollDelay = interval ?? (elapsedTime < 60000 ? 3000 : 10000)
        await waitWithSignal(pollDelay, signal)
        continue
      }

      const elapsedTime = Date.now() - startTime
      const pollDelay = interval ?? (elapsedTime < 60000 ? 3000 : 10000)
      await waitWithSignal(pollDelay, signal)
      attempts++
    }

    throw new Error('Task polling timeout')
  }
}

export function createPpioTransport(settings: PpioTransportSettings): PpioTransport {
  return new PpioTransport(settings)
}

export type { PpioTransport }

View on GitHub (pinned to 726446b54c)

Solutions

  1. Increase maxAttempts (or the per-task interval) when the model is known to be slow — pass a larger options.maxAttempts to pollTaskResult.
  2. Verify with the PPIO dashboard whether the task eventually completed — if so, the budget was just too small.
  3. Retry submit once for a genuinely stuck task; if it stalls repeatedly, report a vendor-side issue.
  4. Surface to the user as 'generation is taking longer than expected' with a cancel/retry affordance.

Example fix

// before
const r = await transport.poll(taskId, { signal })
// after — extend budget for slow models
const r = await transport.poll(taskId, { signal, maxAttempts: 240, interval: 5000 })
Defensive patterns

Strategy: retry

Validate before calling

// Budget the poll loop for slow models
const maxAttempts = slowModel ? 240 : 120
const r = await transport.poll(taskId, { signal, maxAttempts, interval: 5000 })

Type guard

export function isPpioPollingTimeout(e: unknown): boolean {
  return e instanceof Error && e.message === 'Task polling timeout'
}

Try / catch

try {
  await pollUntilDone(transport, taskId, ctx)
} catch (e) {
  if (isPpioPollingTimeout(e)) {
    // check PPIO dashboard: did it eventually finish?
    return { timedOut: true }
  }
  throw e
}

Prevention

When it happens

Trigger: The task remains in TASK_STATUS_QUEUED or TASK_STATUS_PROCESSING across all 120 poll attempts. With the adaptive 3s(<60s)/10s(>60s) interval this is roughly 12–18 minutes. Concrete causes: vendor queue backlog, hung generation, very slow large-image render, or upstream silently stuck.

Common situations: PPIO under heavy load with long queues, a model that takes far longer than the budget, vendor-side hang, or upstream queue starvation.

Understand the failure class

Related errors


AI-assisted analysis of CherryHQ/cherry-studio@726446b54c (2026-08-12). Data as JSON: /api/errors/565348680ddfd5c7. Report an issue: GitHub.