{"record":{"id":"4424cc121a41dfb7","repo":"linshenkx/prompt-optimizer","slug":"failed-to-parse-llm-response-error-instanceof-e","errorCode":null,"errorMessage":"Failed to parse LLM response: ${error instanceof Error ? error.message : String(error)}. Raw content length: ${content.length} characters.","messagePattern":"Failed to parse LLM response: (.+?)\\. Raw content length: (.+?) characters\\.","errorType":"exception","errorClass":"VariableExtractionParseError","httpStatus":null,"severity":"error","filePath":"packages/core/src/services/variable-extraction/service.ts","lineNumber":182,"sourceCode":"    try {\n      // 2. 使用 jsonrepair 修复可能的格式问题\n      const repaired = jsonrepair(jsonText);\n      const parsed = JSON.parse(repaired);\n\n      // 3. 标准化响应\n      return this.normalizeExtractionResponse(parsed);\n    } catch (error) {\n      console.warn(\n        '[VariableExtractionService] Failed to parse JSON:',\n        error instanceof Error ? error.message : String(error)\n      );\n\n      // 尝试直接解析（不通过 jsonrepair）\n      try {\n        const parsed = JSON.parse(jsonText);\n        return this.normalizeExtractionResponse(parsed);\n      } catch (fallbackError) {\n        throw new VariableExtractionParseError(\n          `Failed to parse LLM response: ${error instanceof Error ? error.message : String(error)}. Raw content length: ${content.length} characters.`\n        );\n      }\n    }\n  }\n\n  /**\n   * 标准化提取响应（统一结构）\n   */\n  private normalizeExtractionResponse(data: any): VariableExtractionResponse {\n    if (!data || typeof data !== 'object') {\n      throw new VariableExtractionParseError('Extraction result is not a valid object.');\n    }\n\n    // 验证 variables 字段\n    if (!Array.isArray(data.variables)) {\n      throw new VariableExtractionParseError('Extraction result must have a \"variables\" array.');\n    }","sourceCodeStart":164,"sourceCodeEnd":200,"githubUrl":"https://github.com/linshenkx/prompt-optimizer/blob/3e677b1d9f7e0493c142c175560531e7ae786dce/packages/core/src/services/variable-extraction/service.ts#L164-L200","documentation":"The LLM returned a response, but it could not be parsed into the expected JSON extraction result even after repair attempts — the direct JSON.parse fallback failed too. The message includes the original parser error and the raw content length to help diagnose whether the model returned truncated JSON, prose, or a refusal message.","triggerScenarios":"Calling extract() where the model output is not valid JSON: model wraps JSON in markdown fences or prose (when the stripping logic doesn't catch it), response is truncated by max_tokens, the model returns an empty string or a refusal, or the JSON has trailing commas/quotes that jsonrepair also fails on.","commonSituations":"Small/cheap models that follow JSON instructions poorly; max_tokens set too low so the JSON is cut off mid-array; prompt template modified so the JSON instruction was weakened; model returning Chinese-language preamble before JSON; temperature too high producing malformed output.","solutions":["Increase max_tokens / output limit so the JSON is not truncated (check 'Raw content length' in the message).","Retry with a stronger model or lower temperature for extraction tasks.","Log the raw LLM content to see exactly what came back (markdown fences, prose, refusal) and adjust the template's JSON instruction accordingly.","Enable or improve JSON repair/preprocessing (strip code fences, extract the first {...} block) before JSON.parse."],"exampleFix":"// before\nconst parsed = JSON.parse(jsonText);\n\n// after\nconst m = raw.match(/\\{[\\s\\S]*\\}/);\nconst parsed = JSON.parse(m ? m[0] : jsonText);","handlingStrategy":"retry","validationCode":"const looksLikeJson = (s: string) => /[\\[{]/.test(s);\n// cannot fully validate before the LLM call; use retry with a stricter prompt on failure","typeGuard":"const isParsableJson = (s: string): boolean => { try { JSON.parse(s); return true; } catch { return false; } };","tryCatchPattern":"for (let attempt = 0; attempt < 3; attempt++) {\n  try {\n    return await extractionService.extract({ modelKey, content });\n  } catch (e) {\n    if (e instanceof VariableExtractionParseError && attempt < 2) continue; // retry\n    throw e;\n  }\n}","preventionTips":["Set max_tokens generously so JSON output is never truncated.","Instruct the model to return raw JSON only (no markdown fences, no prose) in the prompt.","Preprocess LLM output: strip code fences and extract the first balanced {...} block before parsing.","Prefer models known to follow JSON output instructions for extraction workloads."],"tags":["llm","json","parse","model-output"],"backgroundTag":"llm-invalid-json-response","analyzedSha":"3e677b1d9f7e0493c142c175560531e7ae786dce","analyzedAt":"2026-08-27T21:29:16.709Z","schemaVersion":2},"datasetVersion":"2026-08-28T00:17:15.603Z"}