{"record":{"id":"e62673e3bf3a672c","repo":"datawhalechina/hello-agents","slug":"http-res-status","errorCode":null,"errorMessage":"HTTP ${res.status}","messagePattern":"HTTP \\$\\{res\\.status\\}","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"Co-creation-projects/Shawnxyxy-HealthRecordAgent/frontend/app.js","lineNumber":301,"sourceCode":"        user_id: userId,\n        context: {\n            today_food_log_text: foodLog,\n            goal: document.getElementById(\"dietGoal\")?.value || \"muscle_gain\",\n            channels: [\"convenience_store\", \"delivery\"],\n            activity_context: document.getElementById(\"dietActivityContext\")?.value?.trim() || \"\",\n            free_notes: document.getElementById(\"dietNotes\")?.value?.trim() || \"\",\n        },\n    };\n\n    try {\n        const res = await fetch(`${API_BASE}/api/diet/recommend`, {\n            method: \"POST\",\n            headers: { \"Content-Type\": \"application/json\" },\n            body: JSON.stringify(body),\n        });\n        const data = await res.json().catch(() => ({}));\n        if (!res.ok) {\n            throw new Error(data.detail ? JSON.stringify(data.detail) : `HTTP ${res.status}`);\n        }\n\n        const runId = data.run_id;\n        try {\n            localStorage.setItem(LAST_DIET_RUN_KEY, runId);\n        } catch (_) { /* ignore */ }\n        const planning = data.planning || {};\n        const ver = data.schema_version || \"1\";\n        const mode = data.pipeline_mode || \"legacy\";\n        const tech = isDeveloperMode();\n\n        let html = \"\";\n        if (tech) {\n            html += `<p><strong>run_id</strong>：<code>${escapeHtml(runId)}</code> &nbsp; <small>schema=${escapeHtml(String(ver))} / ${escapeHtml(String(mode))}</small></p>`;\n        }\n        if (data.degraded) {\n            html += tech\n                ? `<p class=\"banner banner-warning\"><strong>降级</strong>：部分阶段使用规则/模板兜底，请查看 <code>errors</code>。</p>`","sourceCodeStart":283,"sourceCodeEnd":319,"githubUrl":"https://github.com/datawhalechina/hello-agents/blob/606a07d341a47be773fab7f4b71177f53f96b2c3/Co-creation-projects/Shawnxyxy-HealthRecordAgent/frontend/app.js#L283-L319","documentation":"Thrown when POST ${API_BASE}/api/diet/recommend returns a non-OK status. The handler first tries res.json() (with .catch(()=>({})) so a non-JSON body never crashes), then throws either JSON.stringify(data.detail) if the FastAPI-style detail field exists, or the bare 'HTTP <status>' template when the body was empty/unparseable/ lacked detail.","triggerScenarios":"Backend validation failure (422 with structured detail array, which then gets stringified into something like [{\"loc\":...}]), missing user_id or malformed body producing 422, 500 from the diet agent, backend not running so fetch itself rejects instead. Seeing the raw 'HTTP x' form means the error body was empty — typically a crashed worker or a proxy 502.","commonSituations":"FastAPI 422 validation details stringified and shown raw to users; backend restart mid-request; API_BASE pointing at wrong port; CORS blocking so fetch throws TypeError before this line.","solutions":["Reproduce with curl -i to see the real status and body; if 422 compare the request body keys with the endpoint's Pydantic model","If body is empty (this literal message), check backend logs for an unhandled exception in /api/diet/recommend","Pretty-print detail: if Array.isArray(data.detail) map loc/msg fields into a readable string instead of JSON.stringify","Verify API_BASE and that the FastAPI service is listening"],"exampleFix":"// before\nthrow new Error(data.detail ? JSON.stringify(data.detail) : `HTTP ${res.status}`);\n\n// after\nconst detail = Array.isArray(data.detail)\n    ? data.detail.map(d => `${(d.loc||[]).join('.')}: ${d.msg}`).join('; ')\n    : (typeof data.detail === 'string' ? data.detail : '');\nthrow new Error(detail || `HTTP ${res.status} ${res.statusText || ''}`.trim());","handlingStrategy":"try-catch","validationCode":"if (!userId) { showToast('请先选择用户'); return; }","typeGuard":"function isDietResponse(d) { return d && typeof d.run_id === 'string' && typeof d.planning === 'object'; }","tryCatchPattern":"try { const data = await postDietRecommend(body); } catch (e) { renderError(prettifyFastApiDetail(e.message)); }","preventionTips":["Validate form inputs client-side before POSTing","Convert FastAPI array detail into readable text centrally","Log run_id of successful calls to correlate with backend logs"],"tags":["fetch","http","fastapi","validation"],"backgroundTag":null,"analyzedSha":"606a07d341a47be773fab7f4b71177f53f96b2c3","analyzedAt":"2026-08-14T22:57:27.446Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}