{"record":{"id":"9553b48683ef8d8f","repo":"odysseus-dev/odysseus","slug":"pdf-import-failed","errorCode":null,"errorMessage":"PDF import failed","messagePattern":"PDF import failed","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"static/js/document.js","lineNumber":9564,"sourceCode":"      const ext = dotIdx >= 0 ? name.slice(dotIdx).toLowerCase() : '';\n      const baseTitle = dotIdx > 0 ? name.slice(0, dotIdx) : name;\n      const isSpreadsheet = ['.xlsx','.xls','.ods'].includes(ext);\n      const isPdf = ext === '.pdf';\n      // Spreadsheets need the library's per-sheet split — defer to it.\n      if (isSpreadsheet) {\n        openLibrary();\n        requestAnimationFrame(() => requestAnimationFrame(() => document.getElementById('doclib-import-file-btn')?.click()));\n        return;\n      }\n      try {\n        let docId = null;\n        if (isPdf) {\n          const fd = new FormData();\n          fd.append('file', file);\n          const sid = (sessionModule && sessionModule.getCurrentSessionId && sessionModule.getCurrentSessionId()) || _lastSessionId || '';\n          if (sid) fd.append('session_id', sid);\n          const r = await fetch(`${API_BASE}/api/documents/import-pdf`, { method: 'POST', body: fd, credentials: 'same-origin' });\n          if (!r.ok) throw new Error('PDF import failed');\n          const j = await r.json();\n          docId = j.doc_id || j.id;\n        } else {\n          const content = await new Promise((res, rej) => {\n            const reader = new FileReader();\n            reader.onload = () => res(reader.result || '');\n            reader.onerror = () => rej(reader.error);\n            reader.readAsText(file);\n          });\n          const lang = EXT_TO_LANG[ext] !== undefined ? EXT_TO_LANG[ext] : null;\n          const sid = (sessionModule && sessionModule.getCurrentSessionId && sessionModule.getCurrentSessionId()) || _lastSessionId || '';\n          const body = { title: baseTitle, language: lang, content };\n          if (sid) body.session_id = sid;\n          const r = await fetch(`${API_BASE}/api/document`, {\n            method: 'POST',\n            headers: { 'Content-Type': 'application/json' },\n            credentials: 'same-origin',\n            body: JSON.stringify(body),","sourceCodeStart":9546,"sourceCodeEnd":9582,"githubUrl":"https://github.com/odysseus-dev/odysseus/blob/f9235ebbf13f693a6fd29ce70b097f6ec83705bf/static/js/document.js#L9546-L9582","documentation":"Thrown in the file-import handler of static/js/document.js when POST /api/documents/import-pdf (multipart with file and optional session_id) returns non-2xx. The static message 'PDF import failed' discards both the status and any JSON detail the backend provided.","triggerScenarios":"Importing a PDF larger than the upload limit (413), corrupt/encrypted PDF rejected by the parser (400/422), server-side PDF library missing (500), or missing session_id causing a validation error.","commonSituations":"Dragging a password-protected or scanner-corrupted PDF onto the editor; oversized PDFs behind nginx; backend deployed without pdf tooling.","solutions":["Retry with a small, unencrypted PDF to isolate parser vs. transport failure.","Check response body for detail — encrypted or malformed PDFs are usually named there.","Raise upload limits / timeouts if large PDFs fail with 413 or 504.","Include status and detail in the message for diagnosability."],"exampleFix":"// before\nif (!r.ok) throw new Error('PDF import failed');\n\n// after\nif (!r.ok) {\n  let detail = '';\n  try { const j = await r.json(); detail = j?.detail || j?.error || ''; } catch (_) {}\n  throw new Error(`PDF import failed: HTTP ${r.status}${detail ? ` — ${detail}` : ''}`);\n}","handlingStrategy":"try-catch","validationCode":"const isPdf = file.type === 'application/pdf' || file.name.toLowerCase().endsWith('.pdf');\nif (isPdf && file.size > PDF_MAX_BYTES) { if (uiModule) uiModule.showError('PDF too large'); return; }","typeGuard":"function isPdfImportResult(j) {\n  return j != null && typeof j === 'object' && Boolean(j.doc_id || j.id);\n}","tryCatchPattern":"try {\n  const r = await fetch(`${API_BASE}/api/documents/import-pdf`, { method: 'POST', body: fd, credentials: 'same-origin' });\n  if (!r.ok) {\n    let detail = '';\n    try { const j = await r.json(); detail = j?.detail || j?.error || ''; } catch (_) {}\n    throw new Error(`PDF import failed: HTTP ${r.status}${detail ? ' — ' + detail : ''}`);\n  }\n  const j = await r.json();\n  if (!isPdfImportResult(j)) throw new Error('PDF import returned no document id');\n} catch (e) {\n  if (uiModule) uiModule.showError(e.message);\n}","preventionTips":["Reject encrypted PDFs client-side (can't detect reliably — but warn on known-protected workflows).","Match client size caps to the server's multipart limit.","Always pass credentials and include the backend detail in the thrown message."],"tags":["http","pdf-import","multipart","poor-error-message"],"backgroundTag":null,"analyzedSha":"f9235ebbf13f693a6fd29ce70b097f6ec83705bf","analyzedAt":"2026-08-14T21:47:48.359Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}