CherryHQ/cherry-studio · error · Error

Image generation produced ${urls.length} URL(s) but all down

Error message

Image generation produced ${urls.length} URL(s) but all downloads failed

What it means

Error "Image generation produced ${urls.length} URL(s) but all downloads failed" thrown in CherryHQ/cherry-studio.

Source

Thrown at src/main/ai/provider/custom/tasks/imageGenerationJobHandler.ts:224

  const fileManager = application.get('FileManager')
  const files: FileEntry[] = []
  for (const url of urls) {
    if (signal.aborted) throw createAbortError('Image generation aborted')
    const downloaded = await downloadImageAsBase64(url)
    if (!downloaded) continue
    files.push(
      await fileManager.createInternalEntry({
        source: 'base64',
        data: `data:${downloaded.media_type || 'image/png'};base64,${downloaded.data}`,
        cleanupPolicy
      })
    )
  }
  // The remote generation succeeded (it returned URLs); surfacing a hard failure
  // when none could be downloaded avoids reporting a paid generation as an empty,
  // silent success. A partial failure still returns what we have, with a warning.
  if (files.length === 0) {
    throw new Error(`Image generation produced ${urls.length} URL(s) but all downloads failed`)
  }
  if (files.length < urls.length) {
    logger.warn('Some generated image downloads failed', { requested: urls.length, persisted: files.length })
  }
  return files
}

/**
 * Best-effort delete of temp image-input `file_entry` copies. Called by AiService
 * to clean up inputs it created when the job enqueue fails before the job owns
 * them. Once a job is enqueued its inputs are held by `job_file_ref`, and the
 * cleanup pass reclaims them when the job row is pruned — there is no ad-hoc
 * post-job delete (file-entry-cleanup.md §4.1/§5.1). Idempotent and non-throwing.
 */
export async function deleteImageInputEntries(ids: ReadonlyArray<string | undefined>): Promise<void> {
  const present = ids.filter((id): id is string => Boolean(id))
  if (present.length === 0) return
  const fileManager = application.get('FileManager')

View on GitHub (pinned to 726446b54c)

Solutions

  1. Check network connectivity to the CDN hosts serving the image URLs and retry.
  2. Verify the URLs have not expired — some providers sign URLs with short TTLs; download immediately after generation.
  3. Inspect per-download errors in the job logs to see whether failures are 403/expired-signature or timeouts.

Example fix

Download images as soon as the task completes, and on failure surface the underlying HTTP status: fetch(url) then check response.ok before reading the blob.

When it happens

Trigger: The remote generation succeeded and returned one or more image URLs, but every downloadAndPersistImageUrls attempt failed, leaving zero persisted files.

Common situations: Caused by expired/signed URL expiry, network failures, or blocked CDN hosts when fetching generated images. A hard failure is surfaced so a paid generation is not reported as an empty silent success; partial failures still return the files that downloaded, with a warning.


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