{"record":{"id":"813589b7cd909a81","repo":"odysseus-dev/odysseus","slug":"t-res-statustext","errorCode":null,"errorMessage":"t || res.statusText","messagePattern":"t \\|\\| res\\.statusText","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"static/js/document.js","lineNumber":1803,"sourceCode":"    if (!doc) return;\n\n    const instruction = window.prompt(\n      'What should the AI fill in?\\n(e.g. \"My name is Jane Doe, address 123 Main St, dob 1990-01-15\")'\n    );\n    if (!instruction || !instruction.trim()) return;\n\n    _setPdfSaveStatus('saving');\n    const btn = document.getElementById('doc-pdf-ai-fill-btn');\n    if (btn) { btn.disabled = true; btn.textContent = 'Thinking…'; }\n    try {\n      const res = await fetch(`${API_BASE}/api/document/${docId}/ai-fill-annotations`, {\n        method: 'POST',\n        headers: { 'Content-Type': 'application/json' },\n        body: JSON.stringify({ instruction: instruction.trim() }),\n      });\n      if (!res.ok) {\n        const t = await res.text().catch(() => res.statusText);\n        throw new Error(t || res.statusText);\n      }\n      const data = await res.json();\n      const proposed = (data && data.annotations) || [];\n      if (!proposed.length) {\n        _setPdfSaveStatus('idle');\n        if (uiModule && uiModule.showToast) uiModule.showToast('AI found nothing to fill');\n        return;\n      }\n      // Merge into markdown via the same _writeAnnotations path: parse current,\n      // append proposed (each gets a fresh id), persist, then re-render.\n      const existing = _parseAnnotations(doc.content || '');\n      const combined = existing.slice();\n      for (const a of proposed) {\n        combined.push({\n          id: _newAnnotationId(),\n          page: parseInt(a.page, 10) || 1,\n          x: Math.max(0, Math.min(100, parseFloat(a.x) || 0)),\n          y: Math.max(0, Math.min(100, parseFloat(a.y) || 0)),","sourceCodeStart":1785,"sourceCodeEnd":1821,"githubUrl":"https://github.com/odysseus-dev/odysseus/blob/f9235ebbf13f693a6fd29ce70b097f6ec83705bf/static/js/document.js#L1785-L1821","documentation":"Error thrown when AI-assisted annotation filling fails at the HTTP level: POST /api/document/{docId}/ai-fill-annotations with the user instruction returned non-OK. Body text (or statusText) becomes the message; the save pill shows 'AI fill failed: ...'.","triggerScenarios":"POST ai-fill-annotations returns 500 (backend LLM call failed — no API key, provider down, context overflow with a huge PDF), 429 (provider rate limit), 404 (docId unknown), 422 (empty instruction).","commonSituations":"LLM provider credentials missing/expired on the server; model endpoint changed; very large documents blowing the model context; provider outage or rate limiting; user submitted whitespace-only instruction.","solutions":["Read the backend detail in the message; for provider errors, fix the key/endpoint in server config","Retry after a short wait if 429 rate-limited","Reduce document size or fill fields in smaller batches for context-length errors","Check backend logs for the exact provider error"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"const instruction2 = instruction.trim();\nif (!instruction2) { uiModule?.showToast?.('Describe what the AI should fill in'); return; }","typeGuard":null,"tryCatchPattern":"try {\n  const res = await fetch(`${API_BASE}/api/document/${docId}/ai-fill-annotations`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ instruction: instruction.trim() }) });\n  if (!res.ok) {\n    const t = await res.text().catch(() => '');\n    let msg = '';\n    try { msg = JSON.parse(t).detail || ''; } catch { msg = t; }\n    throw new Error(msg || res.statusText || `HTTP ${res.status}`);\n  }\n  const data = await res.json();\n  // ...\n} catch (e) {\n  _setPdfSaveStatus('error', `AI fill failed: ${e.message || e}`);\n} finally {\n  if (btn) { btn.disabled = false; btn.textContent = 'AI fill'; }\n}","preventionTips":["Reject empty instructions client-side to avoid a guaranteed 422","On 429, show a 'rate limited, retry shortly' message instead of the raw body","Always restore the button in finally (already done)"],"tags":["fetch","http-error","ai-fill","llm","document"],"backgroundTag":null,"analyzedSha":"f9235ebbf13f693a6fd29ce70b097f6ec83705bf","analyzedAt":"2026-08-14T21:47:48.359Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}