{"record":{"id":"b737b037f73d8685","repo":"datawhalechina/hello-agents","slug":"error-b737b0","errorCode":null,"errorMessage":"章节生成失败: ","messagePattern":"章节生成失败: ","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"Co-creation-projects/lgs-only-NovelGenerator/frontend/index.html","lineNumber":465,"sourceCode":"                const generateChapters = async () => {\n                    loading.value = true;\n                    currentAction.value = 'chapter';\n                    lastGeneratedChapter.value = null;\n                    \n                    try {\n                        const res = await fetch(`${API_URL}/chapter/generate`, {\n                            method: 'POST',\n                            headers: {'Content-Type': 'application/json'},\n                            body: JSON.stringify({\n                                novel_id: project.novel_id,\n                                title: project.title,\n                                user_input: chapterInput.user_input,\n                                num_chapters: chapterInput.num_chapters,\n                                chapter_length: chapterInput.chapter_length\n                            })\n                        });\n                        \n                        if (!res.ok) throw new Error(await res.text());\n                        \n                        const data = await res.json();\n                        \n                        // 添加新生成的章节到列表\n                        const newChapters = [];\n                        for (const c of data.generated_chapters) {\n                            // 为了能够立即预览，我们需要获取内容。\n                            // 此时我们其实只知道 ID。为了简单，我们立即去 fetch 一次内容，或者后端返回的时候能带上内容最好。\n                            // 查看后端接口，generate 只返回 id, title, summary。\n                            // 所以我们需要单独 fetch 内容用于预览。\n                            const chapterObj = {...c, content: null, loadingContent: false};\n                            chapters.value.push(chapterObj);\n                            newChapters.push(chapterObj);\n                        }\n                        \n                        // 自动加载最后一个生成的章节内容用于预览\n                        if (newChapters.length > 0) {\n                            const lastOne = newChapters[newChapters.length - 1];","sourceCodeStart":447,"sourceCodeEnd":483,"githubUrl":"https://github.com/datawhalechina/hello-agents/blob/606a07d341a47be773fab7f4b71177f53f96b2c3/Co-creation-projects/lgs-only-NovelGenerator/frontend/index.html#L447-L483","documentation":"'章节生成失败: ' + e (chapter generation failed) is alerted by the NovelGenerator frontend when POST {API_URL}/chapter/generate responds non-OK; the thrown Error wraps the raw response text. This is the heaviest endpoint — it asks the LLM to draft N chapters — so failures are frequently timeout/LLM-provider errors rather than simple validation issues. After success the code immediately loops to fetch each chapter's content, so a partial backend success can still leave missing previews.","triggerScenarios":"POST /chapter/generate with {novel_id, title, user_input, num_chapters, chapter_length} returns 404 (stale novel_id / wrong API_URL), 422 (num_chapters/chapter_length wrong type from form inputs), 500 (LLM API failure/timeout — generating multiple chapters in one call is slow), 504 proxy timeout on long generations.","commonSituations":"Form inputs delivering strings where the backend expects ints; LLM key/quota problems; proxy or server timeout too short for multi-chapter generation; project state from an earlier backend run.","solutions":["Read the alert text (server body) — FastAPI validation errors name the exact field; LLM errors name the provider fault.","Coerce num_chapters/chapter_length with Number() before sending and validate ranges.","Increase backend/proxy timeouts, or generate fewer chapters per request.","Verify novel_id is current (project created in this backend session)."],"exampleFix":"// before\nbody: JSON.stringify({\n  novel_id: project.novel_id,\n  title: project.title,\n  user_input: chapterInput.user_input,\n  num_chapters: chapterInput.num_chapters,\n  chapter_length: chapterInput.chapter_length\n})\n\n// after\nbody: JSON.stringify({\n  novel_id: project.novel_id,\n  title: project.title,\n  user_input: chapterInput.user_input,\n  num_chapters: Number(chapterInput.num_chapters),\n  chapter_length: Number(chapterInput.chapter_length)\n})","handlingStrategy":"validation","validationCode":"if (!project.novel_id) { alert('请先创建项目'); return; }\nconst num = Number(chapterInput.num_chapters);\nconst len = Number(chapterInput.chapter_length);\nif (!Number.isInteger(num) || num < 1 || num > 20) { alert('章节数必须是 1-20 的整数'); return; }\nif (!Number.isFinite(len) || len < 100) { alert('章节长度无效'); return; }","typeGuard":"function isChapterGenerateResponse(d: unknown): d is { generated_chapters: Array<{ id: string; title: string; summary: string }> } {\n  return typeof d === 'object' && d !== null && Array.isArray((d as { generated_chapters?: unknown }).generated_chapters);\n}","tryCatchPattern":"try {\n  const res = await fetch(`${API_URL}/chapter/generate`, opts);\n  if (!res.ok) throw new Error(`${res.status}: ${(await res.text()).slice(0, 200)}`);\n  const data = await res.json();\n  if (!isChapterGenerateResponse(data)) throw new Error('章节响应格式异常');\n} catch (e) {\n  alert('章节生成失败: ' + (e instanceof Error ? e.message : String(e)));\n} finally {\n  loading.value = false;\n}","preventionTips":["Coerce form inputs with Number() and range-check before sending — 422s here are almost always type mismatches.","Keep num_chapters small per request; long multi-chapter LLM calls hit proxy timeouts.","Raise backend/proxy timeouts for this endpoint specifically."],"tags":["http","fetch","llm-timeout","type-coercion","novel-generation"],"backgroundTag":null,"analyzedSha":"606a07d341a47be773fab7f4b71177f53f96b2c3","analyzedAt":"2026-08-14T22:57:27.446Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}