odysseus-dev/odysseus · error · Error
Import failed
Error message
Import failed
What it means
Thrown in the same import handler of static/js/document.js for non-PDF files: after reading the file as text, POST /api/document with {title, language, content, session_id} returned non-2xx. 'Import failed' hides the status; common causes mirror the create endpoint's (error 46) but with file-derived payloads.
Source
Thrown at static/js/document.js:9584
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),
});
if (!r.ok) throw new Error('Import failed');
const j = await r.json();
docId = j.id || j.doc_id;
}
if (docId) {
// Fetch the full doc so addDocToTabs has the proper content +
// language fields (it's used downstream by switchToDoc).
try {
const dr = await fetch(`${API_BASE}/api/document/${docId}`, { credentials: 'same-origin' });
const full = dr.ok ? await dr.json() : { id: docId, title: baseTitle };
const sid = (sessionModule && sessionModule.getCurrentSessionId && sessionModule.getCurrentSessionId()) || _lastSessionId || '';
addDocToTabs(full, full.session_id || sid);
switchToDoc(full.id || docId);
} catch (_) {
// Fallback — at least try to switch (may fail silently if not loaded).
addDocToTabs({ id: docId, title: baseTitle }, _lastSessionId || '');
switchToDoc(docId);
}
}View on GitHub (pinned to f9235ebbf1)
Solutions
- Check the response body — 422 responses list the offending field (often language).
- Default language to 'markdown'/'plaintext' when EXT_TO_LANG has no mapping instead of sending null.
- Cap or chunk very large text imports.
- Mirror the status/detail in the thrown message.
Example fix
// before
if (!r.ok) throw new Error('Import failed');
// after
if (!r.ok) {
let detail = '';
try { const j = await r.json(); detail = j?.detail || j?.error || ''; } catch (_) {}
throw new Error(`Import failed: HTTP ${r.status}${detail ? ` — ${detail}` : ''}`);
} Defensive patterns
Strategy: try-catch
Validate before calling
const lang = EXT_TO_LANG[ext] !== undefined ? EXT_TO_LANG[ext] : 'plaintext'; // never send null
if (file.size > TEXT_MAX_BYTES) { if (uiModule) uiModule.showError('File too large'); return; } Try / catch
try {
const r = await fetch(`${API_BASE}/api/document`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, credentials: 'same-origin', body: JSON.stringify(body) });
if (!r.ok) {
let detail = '';
try { const j = await r.json(); detail = j?.detail || ''; } catch (_) {}
throw new Error(`Import failed: HTTP ${r.status}${detail ? ' — ' + detail : ''}`);
}
} catch (e) {
if (uiModule) uiModule.showError(`Could not import ${file.name}: ${e.message}`);
} Prevention
- Default language to a valid value instead of null for unknown extensions.
- Send credentials on every API call uniformly.
- Include the filename and status in the error so batch failures are traceable.
When it happens
Trigger: Importing a .md/.txt/.csv file whose content exceeds a body limit (413), a language value the backend rejects (422 — note EXT_TO_LANG can pass null), missing session (400), or server 500 on insert.
Common situations: Importing huge log-like text files; importing an extension not in EXT_TO_LANG so language is null and the backend schema requires a value; stale session id.
Related errors
AI-assisted analysis of odysseus-dev/odysseus@f9235ebbf1 (2026-08-14).
Data as JSON: /api/errors/c086f3f468ac03d4.
Report an issue: GitHub.