datawhalechina/hello-agents · error · Error

保存失败:

Error message

保存失败: 

What it means

'保存失败: ' + e (save failed) is alerted by the NovelGenerator frontend when PUT {API_URL}/outline/update responds non-OK; the thrown Error wraps the raw response text. The request persists the edited outline {novel_id, title, note_id, content} — so the most common failure is the backend rejecting an outline id that no longer exists (outline.id was set from a previous generate and the backend store changed).

Source

Thrown at Co-creation-projects/lgs-only-NovelGenerator/frontend/index.html:411

                    }
                };

                const updateOutline = async () => {
                    if (!outline.id) return;
                    loading.value = true;
                    currentAction.value = 'update_outline';
                    try {
                        const res = await fetch(`${API_URL}/outline/update`, {
                            method: 'PUT',
                            headers: {'Content-Type': 'application/json'},
                            body: JSON.stringify({
                                novel_id: project.novel_id,
                                title: project.title,
                                note_id: outline.id,
                                content: outline.content
                            })
                        });
                        if (!res.ok) throw new Error(await res.text());
                        alert('大纲保存成功!');
                    } catch (e) {
                        alert('保存失败: ' + e);
                    } finally {
                        loading.value = false;
                        currentAction.value = null;
                    }
                };

                const deleteOutline = async () => {
                    if(!confirm('确定要删除当前大纲吗?此操作不可恢复。')) return;
                    loading.value = true;
                    currentAction.value = 'delete_outline';
                    try {
                        const params = new URLSearchParams({
                            novel_id: project.novel_id,
                            title: project.title,
                            note_id: outline.id

View on GitHub (pinned to 606a07d341)

Solutions

  1. Disable the save button unless outline.id is set (generate must succeed first).
  2. Read the alert text — the server body distinguishes 404 'not found' from validation errors.
  3. If the backend lost state (restart), regenerate the outline to obtain a fresh note_id.
  4. Guard title/content non-empty before the PUT.

Example fix

// before
const updateOutline = async () => { /* no guard */ }

// after
const updateOutline = async () => {
  if (!outline.id) { alert('请先生成大纲'); return; }
  if (!outline.content?.trim()) { alert('大纲内容为空'); return; }
  // ... existing fetch
}
Defensive patterns

Strategy: validation

Validate before calling

if (!outline.id) { alert('请先生成大纲再保存'); return; }
if (!outline.content?.trim()) { alert('大纲内容不能为空'); return; }
if (!project.novel_id || !project.title) { alert('项目信息不完整,请重新加载'); return; }

Type guard

function isOutlineUpdatePayload(p: unknown): p is { novel_id: string; title: string; note_id: string; content: string } {
  return typeof p === 'object' && p !== null
    && typeof (p as { note_id?: unknown }).note_id === 'string'
    && typeof (p as { content?: unknown }).content === 'string';
}

Try / catch

try {
  const res = await fetch(`${API_URL}/outline/update`, opts);
  if (!res.ok) throw new Error(`${res.status}: ${(await res.text()).slice(0, 200)}`);
  alert('大纲保存成功!');
} catch (e) {
  alert('保存失败: ' + (e instanceof Error ? e.message : String(e)));
} finally {
  loading.value = false;
}

Prevention

When it happens

Trigger: PUT /outline/update returns 404 (note_id/novel_id unknown — backend restarted, outline deleted elsewhere, outline.id never set because generate failed earlier), 422 (missing required fields such as empty title), 500 (storage/write failure). Clicking save before any outline was generated leaves outline.id null → guaranteed rejection.

Common situations: Saving with no outline loaded (id null); backend memory store reset between generate and save; concurrent edits deleting the note; required field omitted in the edit.

Related errors


AI-assisted analysis of datawhalechina/hello-agents@606a07d341 (2026-08-14). Data as JSON: /api/errors/eb9cd65115abc158. Report an issue: GitHub.