{"record":{"id":"def231d60264c9ef","repo":"CherryHQ/cherry-studio","slug":"invalid-json-response-from-siliconflow","errorCode":null,"errorMessage":"Invalid JSON response from SiliconFlow","messagePattern":"Invalid JSON response from SiliconFlow","errorType":"exception","errorClass":"APICallError","httpStatus":null,"severity":"error","filePath":"src/main/ai/provider/custom/silicon/SiliconImageModel.ts","lineNumber":130,"sourceCode":"    })\n    const responseBody = await response.text()\n\n    if (!response.ok) {\n      throw new APICallError({\n        message: responseBody || response.statusText,\n        url,\n        requestBodyValues: body,\n        statusCode: response.status,\n        responseHeaders,\n        responseBody\n      })\n    }\n\n    let parsed: ImageResponseBody\n    try {\n      parsed = JSON.parse(responseBody) as ImageResponseBody\n    } catch (cause) {\n      throw new APICallError({\n        message: 'Invalid JSON response from SiliconFlow',\n        cause,\n        url,\n        requestBodyValues: body,\n        statusCode: response.status,\n        responseHeaders,\n        responseBody\n      })\n    }\n\n    const items = parsed.images ?? parsed.data ?? []\n    const images: string[] = items.flatMap((item) => {\n      if (typeof item.b64_json === 'string') return [item.b64_json]\n      if (typeof item.url === 'string') return [item.url]\n      return []\n    })\n\n    return {","sourceCodeStart":112,"sourceCodeEnd":148,"githubUrl":"https://github.com/CherryHQ/cherry-studio/blob/726446b54cd69ffe51a276638672f6d95ca0768c/src/main/ai/provider/custom/silicon/SiliconImageModel.ts#L112-L148","documentation":"APICallError thrown when SiliconImageModel.doGenerate receives an ok HTTP status but the body is not valid JSON (JSON.parse throws). The original parse error is attached as `cause`. This guards against the SDK handing a parse error to image-decoding logic downstream; the response body is preserved on the error for inspection.","triggerScenarios":"SiliconFlow returns 2xx but the body is HTML (a CDN/proxy error page), empty, truncated, or otherwise non-JSON. Concrete causes: gateway/CDN serving an HTML error page with 200, partial response due to connection drop, vendor maintenance returning an HTML banner, or a reverse-proxy injecting content.","commonSituations":"Vendor outage behind a CDN returning a friendly HTML error page, corporate proxy rewriting responses, mid-stream disconnect leaving truncated body, or a regional gateway returning an HTML interstitial.","solutions":["Inspect error.responseBody — if it is HTML or empty, the request never reached the real SiliconFlow API; treat as transient and retry.","Verify the configured baseURL resolves to the real siliconflow.cn API and not a captive portal/proxy page.","Check network egress for transparent proxies rewriting the response.","If intermittent, add a retry with backoff; if persistent, report a vendor/network issue."],"exampleFix":"// before\nparsed = JSON.parse(responseBody) as ImageResponseBody\n// after — guard and surface what we got\nlet parsed: ImageResponseBody\ntry { parsed = JSON.parse(responseBody) as ImageResponseBody }\n catch (cause) { throw new APICallError({ message: `SiliconFlow returned non-JSON body (len=${responseBody.length}): ${responseBody.slice(0,200)}`, cause, ... }) }","handlingStrategy":"retry","validationCode":"// Pre-check reachability if a captive portal / proxy is suspected\nconst probe = await fetch(baseURL, { method: 'HEAD' })\nconst ct = probe.headers.get('content-type') ?? ''\nif (ct.includes('text/html')) throw new Error('SiliconFlow endpoint returned HTML; check baseURL/proxy')","typeGuard":"export function isSiliconNonJsonError(e: unknown): boolean {\n  return e instanceof APICallError && /Invalid JSON response from SiliconFlow/.test(e.message)\n}","tryCatchPattern":"try {\n  await imageModel.doGenerate(opts)\n} catch (e) {\n  if (isSiliconNonJsonError(e)) {\n    // CDN/gateway returned HTML; retry once\n    await backoffRetry(() => imageModel.doGenerate(opts), { maxAttempts: 1 })\n  }\n  throw e\n}","preventionTips":["Verify baseURL resolves to the real siliconflow.cn API, not a captive portal.","Treat non-JSON 2xx as transient and retry once.","Inspect error.responseBody — HTML or empty signals a network/proxy issue, not a vendor API error."],"tags":["siliconflow","parse-error","json","network","image-generation"],"backgroundTag":null,"analyzedSha":"726446b54cd69ffe51a276638672f6d95ca0768c","analyzedAt":"2026-08-12T17:30:37.448Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}