{"record":{"id":"cc1c2f1d5a88f579","repo":"CherryHQ/cherry-studio","slug":"image-generation-failed","errorCode":null,"errorMessage":"Image generation failed","messagePattern":"Image generation failed","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/main/ai/AiService.ts","lineNumber":960,"sourceCode":"\n    let snapshot: JobSnapshot\n    try {\n      snapshot = await handle.finished\n    } finally {\n      signal?.removeEventListener('abort', onAbort)\n    }\n\n    if (snapshot.status === 'completed') {\n      const output = snapshot.output as ImageGenerationJobOutput | null\n      return { files: output?.files ?? [] }\n    }\n    if (snapshot.status === 'cancelled') {\n      throw new DOMException('Image generation aborted', 'AbortError')\n    }\n    // `||` not `??`: a job can fail with an empty-string error message (a vendor that\n    // returns a non-OK response with no body), which would otherwise surface as a\n    // message-less `Error` the renderer can't show.\n    throw new Error(snapshot.error?.message || 'Image generation failed')\n  }\n\n  // ── Embedding ──\n\n  async embedMany(request: AsInProcess<AiEmbedRequest>): Promise<AiEmbedResult> {\n    logger.info('embedMany started', { assistantId: request.assistantId, count: request.values.length })\n    const signal = request.requestOptions?.signal\n\n    const { sdkConfig, credentialReceipt, provider, model, assistant } = await this.buildAgentParamsFor(request, signal)\n    const usageContext = createCaptureContext({\n      provider,\n      model,\n      sdkModelId: sdkConfig.modelId,\n      credentialReceipt,\n      source: sourceSnapshotForAssistant(assistant),\n      messageRef: null\n    })\n","sourceCodeStart":942,"sourceCodeEnd":978,"githubUrl":"https://github.com/CherryHQ/cherry-studio/blob/726446b54cd69ffe51a276638672f6d95ca0768c/src/main/ai/AiService.ts#L942-L978","documentation":"Thrown by AiService.generateImage when an image-generation job finishes in a non-completed, non-cancelled state (i.e. 'failed', or any unrecognized terminal status). The fallback string 'Image generation failed' is used only when snapshot.error?.message is empty/falsy — the code uses || (not ??) deliberately so that a vendor returning a non-OK response with an empty body still surfaces a human-readable message rather than a message-less Error. A cancelled job throws an AbortError DOMException instead and never reaches this line.","triggerScenarios":"The underlying image vendor returned an error (rate limit, auth failure, content-policy rejection, malformed request, model unavailable); the job handler threw during processing; the network request errored; or the vendor returned a non-OK status with no error body, yielding the generic fallback message.","commonSituations":"Expired or invalid API key; exceeded quota/rate limit; prompt rejected by content filter; unsupported image model id; vendor outage or 5xx; misconfigured base URL pointing at a non-image endpoint; malformed request payload (wrong parameters for the selected model).","solutions":["Inspect snapshot.error?.message in logs (or the toast) — if present it carries the vendor's reason; address that root cause (auth, quota, content policy).","Verify the provider credentials and base URL are correct and that the selected model supports image generation.","Retry after ruling out a transient vendor error; for rate limits, back off.","If the message is the generic fallback (empty vendor message), enable request/response logging for the image provider to capture the raw vendor response and adjust the request accordingly."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  const result = await aiService.generateImage(req, { signal })\n  // use result.files\n} catch (err) {\n  if (err instanceof DOMException && err.name === 'AbortError') {\n    // user cancelled — handle gracefully\n    return\n  }\n  // surfaced vendor/generic error — show err.message to the user, offer retry\n  showErrorToast(err instanceof Error ? err.message : 'Image generation failed')\n}","preventionTips":["Validate provider credentials, base URL, and model id before invoking image generation.","Handle AbortError separately so user-cancelled jobs do not show as failures.","Log snapshot.error?.message and the raw vendor response when the message is the generic fallback, to diagnose empty-body vendor errors.","Retry transient vendor errors with backoff, but surface auth/quota/content-policy errors to the user."],"tags":["ai","image-generation","runtime","vendor-error"],"backgroundTag":null,"analyzedSha":"726446b54cd69ffe51a276638672f6d95ca0768c","analyzedAt":"2026-08-12T17:30:37.448Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}