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.

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)

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.