CherryHQ/cherry-studio · error · DashScopeTaskFailedError

DashScope task ${status.toLowerCase()}

Error message

DashScope task ${status.toLowerCase()}

What it means

Thrown as a `DashScopeTaskFailedError` during polling when `task_status` is `FAILED`, `CANCELED`, or `UNKNOWN`. The message is the vendor-provided `output.message` if present, otherwise a generic `DashScope task {status}`. This is a terminal condition — the remote async task will never produce images.

Source

Thrown at src/main/ai/provider/custom/dashscope/dashscopeTransport.ts:467

    let attempts = 0
    let transientRetries = 0
    const startTime = Date.now()

    while (attempts < maxAttempts) {
      if (signal?.aborted) throw createAbortError('Task polling aborted')

      try {
        const result = await this.request<DashScopeTaskResult>(
          `/api/v1/tasks/${encodeURIComponent(taskId)}`,
          'GET',
          undefined,
          { timeout: 10000, signal }
        )
        transientRetries = 0
        const status = result.output.task_status
        if (status === 'SUCCEEDED') return result
        if (status === 'FAILED' || status === 'CANCELED' || status === 'UNKNOWN') {
          throw new DashScopeTaskFailedError(result.output.message || `DashScope task ${status.toLowerCase()}`)
        }
      } catch (error) {
        if (signal?.aborted || (error instanceof Error && error.name === 'AbortError')) {
          throw createAbortError('Task polling aborted')
        }
        // A terminal vendor failure or a 4xx (bar 429) poll response ends the
        // loop; 5xx / 429 fall through to transient retry.
        if (error instanceof DashScopeTaskFailedError) throw error
        if (error instanceof DashScopeApiError && isTerminalHttpStatus(error.statusCode)) throw error

        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

View on GitHub (pinned to 726446b54c)

Solutions

  1. Inspect the error message (vendor `output.message`) for the specific rejection reason and adjust the prompt/parameters accordingly.
  2. Retry the generation — content-moderation and some quota failures are per-request.
  3. Verify account quota/billing status in the DashScope (Bailian) console.
Defensive patterns

Strategy: try-catch

Type guard

const isDashScopeTaskFailedError = (e: unknown): e is DashScopeTaskFailedError =>
  e instanceof Error && e.name === 'DashScopeTaskFailedError'

Try / catch

try {
  urls = await transport.poll(taskId, { signal })
} catch (e) {
  if (e instanceof DashScopeTaskFailedError) {
    // terminal vendor failure — surface e.message (vendor reason) to the user; do not retry blindly
    throw new Error(`Image generation failed: ${e.message}`)
  }
  throw e
}

Prevention

When it happens

Trigger: The async image task ended in a non-success terminal state: content-moderation rejection, invalid generation parameters, quota/billing exhaustion, or an explicit vendor-side cancellation.

Common situations: Prompt or input image tripped DashScope's content filter; the account hit a concurrency/quota limit; unsupported parameter combination for the model; transient vendor outage marked the task UNKNOWN.

Related errors


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