{"record":{"id":"c086f3f468ac03d4","repo":"odysseus-dev/odysseus","slug":"import-failed","errorCode":null,"errorMessage":"Import failed","messagePattern":"Import failed","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"static/js/document.js","lineNumber":9584,"sourceCode":"          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),\n          });\n          if (!r.ok) throw new Error('Import failed');\n          const j = await r.json();\n          docId = j.id || j.doc_id;\n        }\n        if (docId) {\n          // Fetch the full doc so addDocToTabs has the proper content +\n          // language fields (it's used downstream by switchToDoc).\n          try {\n            const dr = await fetch(`${API_BASE}/api/document/${docId}`, { credentials: 'same-origin' });\n            const full = dr.ok ? await dr.json() : { id: docId, title: baseTitle };\n            const sid = (sessionModule && sessionModule.getCurrentSessionId && sessionModule.getCurrentSessionId()) || _lastSessionId || '';\n            addDocToTabs(full, full.session_id || sid);\n            switchToDoc(full.id || docId);\n          } catch (_) {\n            // Fallback — at least try to switch (may fail silently if not loaded).\n            addDocToTabs({ id: docId, title: baseTitle }, _lastSessionId || '');\n            switchToDoc(docId);\n          }\n        }","sourceCodeStart":9566,"sourceCodeEnd":9602,"githubUrl":"https://github.com/odysseus-dev/odysseus/blob/f9235ebbf13f693a6fd29ce70b097f6ec83705bf/static/js/document.js#L9566-L9602","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nif (!r.ok) throw new Error('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(`Import failed: HTTP ${r.status}${detail ? ` — ${detail}` : ''}`);\n}","handlingStrategy":"try-catch","validationCode":"const lang = EXT_TO_LANG[ext] !== undefined ? EXT_TO_LANG[ext] : 'plaintext'; // never send null\nif (file.size > TEXT_MAX_BYTES) { if (uiModule) uiModule.showError('File too large'); return; }","typeGuard":null,"tryCatchPattern":"try {\n  const r = await fetch(`${API_BASE}/api/document`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, credentials: 'same-origin', body: JSON.stringify(body) });\n  if (!r.ok) {\n    let detail = '';\n    try { const j = await r.json(); detail = j?.detail || ''; } catch (_) {}\n    throw new Error(`Import failed: HTTP ${r.status}${detail ? ' — ' + detail : ''}`);\n  }\n} catch (e) {\n  if (uiModule) uiModule.showError(`Could not import ${file.name}: ${e.message}`);\n}","preventionTips":["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."],"tags":["http","file-import","document-create","poor-error-message"],"backgroundTag":null,"analyzedSha":"f9235ebbf13f693a6fd29ce70b097f6ec83705bf","analyzedAt":"2026-08-14T21:47:48.359Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}