CherryHQ/cherry-studio · error · APICallError

responseBody || response.statusText

Error message

responseBody || response.statusText

What it means

APICallError is the AI SDK's standard error for a failed provider HTTP call. SiliconImageModel.doGenerate throws it when SiliconFlow's /images/generations returns non-ok. The message is the raw response body (or response.statusText if the body is empty), and the error carries url, statusCode, responseHeaders, requestBodyValues, and responseBody for diagnostics.

Solutions

  1. Read error.statusCode and error.message: 401 → fix apiKey; 402/429 → top up balance / back off; 400/422 → inspect the body for the offending field (often image_size or model id); 5xx → retry.
  2. Confirm the model id is valid for SiliconFlow image generation (Kolors, Qwen-Image, FLUX, Z-Image, etc.).
  3. Validate image_size against SiliconFlow's supported list before submit.
  4. For transient 5xx, retry with exponential backoff at the call site.

Example fix

// before
throw new APICallError({ message: responseBody || response.statusText, statusCode: response.status, ... })
// after — also surface the model id and a hint
throw new APICallError({
  message: `SiliconFlow image generation for '${this.modelId}' failed (${response.status}): ${responseBody || response.statusText}`,
  statusCode: response.status, url, requestBodyValues: body, responseHeaders, responseBody
})
Defensive patterns

Strategy: try-catch

Validate before calling

if (!settings.apiKey) throw new Error('SiliconFlow apiKey is required')
if (size && !SILICON_SUPPORTED_SIZES.includes(size)) {
  throw new Error(`Unsupported image_size '${size}' for SiliconFlow`)
}

Type guard

import { APICallError } from '@ai-sdk/provider'
export function isSiliconApiError(e: unknown): e is APICallError {
  return e instanceof APICallError && typeof e.statusCode === 'number' && /silicon/i.test(e.url ?? '')
}

Try / catch

try {
  await imageModel.doGenerate(opts)
} catch (e) {
  if (e instanceof APICallError && (e.statusCode ?? 0) >= 500) {
    await backoffRetry(() => imageModel.doGenerate(opts))
  }
  throw e
}

Prevention

When it happens

Trigger: POST /images/generations to siliconflow.cn returns 4xx/5xx. Concrete causes: missing/invalid API key (401), insufficient balance (402/429), unknown model id (400/404), unsupported image_size value (422), NSFW rejection, malformed prompt, or 5xx during outage.

Common situations: First run with unset apiKey, balance exhausted mid-batch, model id drift after SiliconFlow renames, invalid image_size (must be a supported WxH), aspectRatio passed but unsupported, or transient 5xx.

Related errors


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

Appendix: source

Thrown at src/main/ai/provider/custom/silicon/SiliconImageModel.ts:116

    const url = this.config.url({ path: '/images/generations', modelId: this.modelId })
    const fetchFn = this.config.fetch ?? globalThis.fetch
    const response = await fetchFn(url, {
      method: 'POST',
      headers: removeUndefinedEntries(
        combineHeaders(this.config.headers(), headers, { 'Content-Type': 'application/json' })
      ),
      body: JSON.stringify(body),
      signal: abortSignal
    })

    const responseHeaders: Record<string, string> = {}
    response.headers.forEach((value, key) => {
      responseHeaders[key] = value
    })
    const responseBody = await response.text()

    if (!response.ok) {
      throw new APICallError({
        message: responseBody || response.statusText,
        url,
        requestBodyValues: body,
        statusCode: response.status,
        responseHeaders,
        responseBody
      })
    }

    let parsed: ImageResponseBody
    try {
      parsed = JSON.parse(responseBody) as ImageResponseBody
    } catch (cause) {
      throw new APICallError({
        message: 'Invalid JSON response from SiliconFlow',
        cause,
        url,
        requestBodyValues: body,

View on GitHub (pinned to 726446b54c)