{"record":{"id":"c0f5ba176d62f759","repo":"linshenkx/prompt-optimizer","slug":"api-error-json-stringify-error-response-data","errorCode":null,"errorMessage":"API error: ${JSON.stringify(error.response.data)}","messagePattern":"API error: (.+?)","errorType":"exception","errorClass":"APIError","httpStatus":null,"severity":"error","filePath":"packages/core/src/services/llm/adapters/openai-adapter.ts","lineNumber":183,"sourceCode":"      throw new APIError('Unexpected API response format')\n    } catch (error: any) {\n      console.error('[OpenAIAdapter] Failed to fetch models:', error)\n\n      // 连接错误处理（包括跨域检测）\n      if (error.message && (error.message.includes('Failed to fetch') ||\n          error.message.includes('Connection error'))) {\n        const isCrossOriginError = this.detectCrossOriginError(error, baseURL)\n\n        if (isCrossOriginError) {\n          throw new APIError(`Cross-origin connection failed: ${error.message}`)\n        } else {\n          throw new APIError(`Connection failed: ${error.message}`)\n        }\n      }\n\n      // API返回的错误信息\n      if (error.response?.data) {\n        throw new APIError(`API error: ${JSON.stringify(error.response.data)}`)\n      }\n\n      // 其他错误,保持原始信息\n      throw new APIError(error.message || 'Unknown error')\n    }\n  }\n\n  // ===== 参数定义（用于buildDefaultModel） =====\n\n  /**\n   * 获取参数定义\n   * 基于 OpenAI 官方文档: https://platform.openai.com/docs/api-reference/chat/create\n   */\n  protected getParameterDefinitions(_modelId: string): readonly ParameterDefinition[] {\n    return [\n      {\n        name: 'reasoning_effort',\n        labelKey: 'params.reasoning_effort.label',","sourceCodeStart":165,"sourceCodeEnd":201,"githubUrl":"https://github.com/linshenkx/prompt-optimizer/blob/3e677b1d9f7e0493c142c175560531e7ae786dce/packages/core/src/services/llm/adapters/openai-adapter.ts#L165-L201","documentation":"The OpenAI-compatible request failed and the error carried an axios-style error.response.data payload (a structured provider error body). The adapter JSON-stringifies that body into the APIError message so the provider's error detail (code, message) is preserved.","triggerScenarios":"Provider returned 4xx/5xx with a JSON error body: invalid API key, model not found, insufficient quota, context length exceeded — surfaced during getModelsAsync.","commonSituations":"401 invalid_api_key, 404 model_not_found after renaming, 429 rate_limit_exceeded, billing/quota exhausted on OpenAI or a compatible gateway.","solutions":["Read the embedded JSON: code/message fields identify the exact provider error","invalid_api_key → fix connectionConfig.apiKey","model_not_found → update the model ID in config","429/quota → retry with backoff and check billing limits"],"exampleFix":"// before\ncatch (e) { console.log(e.message) } // opaque JSON string\n\n// after\ncatch (e: any) {\n  const m = /API error: (.*)$/.exec(e.message)\n  const detail = m ? JSON.parse(m[1]) : null\n  if (detail?.code === 'invalid_api_key') refreshKey()\n}","handlingStrategy":"try-catch","validationCode":"null","typeGuard":"function parseProviderApiError(e: unknown): { code?: string; message?: string } | null {\n  if (!(e instanceof APIError)) return null\n  const m = /API error: (.*)$/.exec(e.message)\n  try { return m ? JSON.parse(m[1]) : null } catch { return null }\n}","tryCatchPattern":"try { await adapter.getModelsAsync() }\ncatch (e) {\n  const detail = parseProviderApiError(e)\n  if (detail?.code === 'invalid_api_key') return rotateKey()\n  if (detail?.code === 'rate_limit_exceeded') return backoffRetry(fn)\n  throw e\n}","preventionTips":["Parse the embedded JSON instead of string-matching","Rotate keys automatically on 401","Set billing/quota alerts on provider dashboards"],"tags":["openai","api-error","http-status","provider-error"],"backgroundTag":"llm-api-http-error","analyzedSha":"3e677b1d9f7e0493c142c175560531e7ae786dce","analyzedAt":"2026-08-27T21:29:16.709Z","schemaVersion":2},"datasetVersion":"2026-08-28T00:17:15.603Z"}