{"record":{"id":"b6efddfb72340574","repo":"odysseus-dev/odysseus","slug":"pdf-import-failed-e","errorCode":null,"errorMessage":"PDF import failed: ${_e}","messagePattern":"PDF import failed: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"static/js/documentLibrary.js","lineNumber":1525,"sourceCode":"        const language = EXT_TO_LANG[ext] !== undefined ? EXT_TO_LANG[ext] : null;\n\n        const isSpreadsheet = ['.xlsx', '.xls', '.ods'].includes(ext);\n        const isPdf = ext === '.pdf';\n\n        if (isPdf) {\n          // Backend handles save + AcroForm detection in one shot — picks the\n          // right doc kind so fillable forms get clickable inputs in the PDF\n          // view, and plain PDFs get the static page-image viewer.\n          const fd = new FormData();\n          fd.append('file', file);\n          const res = await fetch(`${API_BASE}/api/documents/import-pdf`, {\n            method: 'POST',\n            body: fd,\n          });\n          if (!res.ok) {\n            let _e = `HTTP ${res.status}`;\n            try { const _j = await res.json(); _e = _j.detail || _j.error || _e; } catch {}\n            throw new Error('PDF import failed: ' + _e);\n          }\n          imported++;\n          continue;\n        }\n\n        if (isSpreadsheet) {\n          // Multi-sheet: create one document per sheet\n          await ensureXLSX();\n          const buf = await file.arrayBuffer();\n          const wb = window.XLSX.read(buf, { type: 'array' });\n          for (const sheetName of wb.SheetNames) {\n            const csv = window.XLSX.utils.sheet_to_csv(wb.Sheets[sheetName]);\n            if (!csv.trim()) continue;\n            const sheetTitle = wb.SheetNames.length > 1\n              ? `${baseTitle} - ${sheetName}` : baseTitle;\n            const res = await fetch(`${API_BASE}/api/document`, {\n              method: 'POST',\n              headers: { 'Content-Type': 'application/json' },","sourceCodeStart":1507,"sourceCodeEnd":1543,"githubUrl":"https://github.com/odysseus-dev/odysseus/blob/f9235ebbf13f693a6fd29ce70b097f6ec83705bf/static/js/documentLibrary.js#L1507-L1543","documentation":"Thrown in documentLibrary.js's batch importer when POST /api/documents/import-pdf for a dropped PDF returns non-2xx. This is the better-diagnosed sibling of error 51: it extracts _j.detail/_j.error and prefixes 'PDF import failed: ', so the surfaced message in the end-of-import summary ('Imported N files, M failed — <first error>') carries the backend reason.","triggerScenarios":"Batch-importing PDFs where one is encrypted/corrupt (422 with detail), exceeds the multipart size cap (413), or the backend PDF stack errors (500). Only the first failure's message survives into the summary (_firstErr), so later distinct causes are hidden.","commonSituations":"Mixing valid and password-protected PDFs in one drop; office scanners producing non-standard PDFs; proxy body limits on multi-MB scans.","solutions":["Read the _firstErr suffix of the summary toast — it is the backend's detail for the first failing file.","Import the failing file alone to confirm which one it is.","Remove encryption/repair the PDF (qpdf --decrypt) and retry.","Raise upload size/time limits if large scans are legitimate."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"if (file.type !== 'application/pdf' && !file.name.toLowerCase().endsWith('.pdf')) continue;\nif (file.size > PDF_MAX_BYTES) { failed++; _firstErr ||= `${file.name}: too large`; continue; }","typeGuard":null,"tryCatchPattern":"try {\n  const res = await fetch(`${API_BASE}/api/documents/import-pdf`, { method: 'POST', body: fd, credentials: 'same-origin' });\n  if (!res.ok) {\n    let _e = `HTTP ${res.status}`;\n    try { const _j = await res.json(); _e = _j.detail || _j.error || _e; } catch {}\n    throw new Error(`PDF import failed (${file.name}): ` + _e);\n  }\n  imported++;\n} catch (e) {\n  failed++;\n  if (!_firstErr) _firstErr = (e && e.message) || String(e);\n}","preventionTips":["Include the filename in per-file errors so multi-file failures are attributable (only _firstErr reaches the summary).","Pre-check size and encryption where possible before the POST.","Add credentials to the multipart request for auth-required deployments."],"tags":["http","pdf-import","batch-import","multipart"],"backgroundTag":null,"analyzedSha":"f9235ebbf13f693a6fd29ce70b097f6ec83705bf","analyzedAt":"2026-08-14T21:47:48.359Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}