odysseus-dev/odysseus · error · Error

PDF import failed

Error message

PDF import failed

What it means

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.

Source

Thrown at static/js/document.js:9564

      const ext = dotIdx >= 0 ? name.slice(dotIdx).toLowerCase() : '';
      const baseTitle = dotIdx > 0 ? name.slice(0, dotIdx) : name;
      const isSpreadsheet = ['.xlsx','.xls','.ods'].includes(ext);
      const isPdf = ext === '.pdf';
      // Spreadsheets need the library's per-sheet split — defer to it.
      if (isSpreadsheet) {
        openLibrary();
        requestAnimationFrame(() => requestAnimationFrame(() => document.getElementById('doclib-import-file-btn')?.click()));
        return;
      }
      try {
        let docId = null;
        if (isPdf) {
          const fd = new FormData();
          fd.append('file', file);
          const sid = (sessionModule && sessionModule.getCurrentSessionId && sessionModule.getCurrentSessionId()) || _lastSessionId || '';
          if (sid) fd.append('session_id', sid);
          const r = await fetch(`${API_BASE}/api/documents/import-pdf`, { method: 'POST', body: fd, credentials: 'same-origin' });
          if (!r.ok) throw new Error('PDF import failed');
          const j = await r.json();
          docId = j.doc_id || j.id;
        } else {
          const content = await new Promise((res, rej) => {
            const reader = new FileReader();
            reader.onload = () => res(reader.result || '');
            reader.onerror = () => rej(reader.error);
            reader.readAsText(file);
          });
          const lang = EXT_TO_LANG[ext] !== undefined ? EXT_TO_LANG[ext] : null;
          const sid = (sessionModule && sessionModule.getCurrentSessionId && sessionModule.getCurrentSessionId()) || _lastSessionId || '';
          const body = { title: baseTitle, language: lang, content };
          if (sid) body.session_id = sid;
          const r = await fetch(`${API_BASE}/api/document`, {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            credentials: 'same-origin',
            body: JSON.stringify(body),

View on GitHub (pinned to f9235ebbf1)

Solutions

  1. Retry with a small, unencrypted PDF to isolate parser vs. transport failure.
  2. Check response body for detail — encrypted or malformed PDFs are usually named there.
  3. Raise upload limits / timeouts if large PDFs fail with 413 or 504.
  4. Include status and detail in the message for diagnosability.

Example fix

// before
if (!r.ok) throw new Error('PDF import failed');

// after
if (!r.ok) {
  let detail = '';
  try { const j = await r.json(); detail = j?.detail || j?.error || ''; } catch (_) {}
  throw new Error(`PDF import failed: HTTP ${r.status}${detail ? ` — ${detail}` : ''}`);
}
Defensive patterns

Strategy: try-catch

Validate before calling

const isPdf = file.type === 'application/pdf' || file.name.toLowerCase().endsWith('.pdf');
if (isPdf && file.size > PDF_MAX_BYTES) { if (uiModule) uiModule.showError('PDF too large'); return; }

Type guard

function isPdfImportResult(j) {
  return j != null && typeof j === 'object' && Boolean(j.doc_id || j.id);
}

Try / catch

try {
  const r = await fetch(`${API_BASE}/api/documents/import-pdf`, { method: 'POST', body: fd, credentials: 'same-origin' });
  if (!r.ok) {
    let detail = '';
    try { const j = await r.json(); detail = j?.detail || j?.error || ''; } catch (_) {}
    throw new Error(`PDF import failed: HTTP ${r.status}${detail ? ' — ' + detail : ''}`);
  }
  const j = await r.json();
  if (!isPdfImportResult(j)) throw new Error('PDF import returned no document id');
} catch (e) {
  if (uiModule) uiModule.showError(e.message);
}

Prevention

When it happens

Trigger: 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.

Common situations: Dragging a password-protected or scanner-corrupted PDF onto the editor; oversized PDFs behind nginx; backend deployed without pdf tooling.

Related errors


AI-assisted analysis of odysseus-dev/odysseus@f9235ebbf1 (2026-08-14). Data as JSON: /api/errors/9553b48683ef8d8f. Report an issue: GitHub.