{"record":{"id":"1cc33b47012b98c7","repo":"odysseus-dev/odysseus","slug":"no-contact-data-found","errorCode":null,"errorMessage":"No contact data found","messagePattern":"No contact data found","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"warning","filePath":"static/js/settings.js","lineNumber":4169,"sourceCode":"          if (name.endsWith('.csv') || !String(text || '').toUpperCase().includes('BEGIN:VCARD')) csvParts.push(text);\n          else vcfParts.push(text);\n        });\n        let imported = 0, total = 0, failed = 0;\n        const _postImport = async (body) => {\n          const r = await fetch('/api/contacts/import', {\n            method: 'POST', credentials: 'same-origin',\n            headers: { 'Content-Type': 'application/json' },\n            body: JSON.stringify(body),\n          });\n          const d = await r.json();\n          if (d.error) throw new Error(d.error);\n          imported += Number(d.imported || 0);\n          total += Number(d.total || 0);\n          failed += Number(d.failed || 0);\n        };\n        if (vcfParts.length) await _postImport({ vcf: vcfParts.join('\\n') });\n        if (csvParts.length) await _postImport({ csv: csvParts.join('\\n') });\n        if (!vcfParts.length && !csvParts.length) throw new Error('No contact data found');\n        const msg = `Imported ${imported}/${total}` + (failed ? ` (${failed} failed)` : '');\n        uiModule.showToast ? uiModule.showToast(msg) : null;\n      } catch (err) {\n        uiModule.showError ? uiModule.showError(err?.message || 'Import failed') : alert(err?.message || 'Import failed');\n      } finally {\n        if (btn) { btn.textContent = orig; btn.disabled = false; }\n        e.target.value = '';\n        await _renderContactsManager();\n      }\n    });\n    await _renderContactsManager();\n  }\n\n  // Render the contacts list inside the manager card with inline edit +\n  // delete. Each row: name + emails; pencil flips to editable inputs.\n  async function _renderContactsManager() {\n    const list = el('cm-list');\n    if (!list) return;","sourceCodeStart":4151,"sourceCodeEnd":4187,"githubUrl":"https://github.com/odysseus-dev/odysseus/blob/f9235ebbf13f693a6fd29ce70b097f6ec83705bf/static/js/settings.js#L4151-L4187","documentation":"Thrown after reading the selected import files when neither vcfParts nor csvParts has content — the content-sniffing logic (extension .csv OR absence of 'BEGIN:VCARD') classified every file into neither bucket, which cannot normally happen, so in practice this fires when the file list itself is empty or reads returned empty text.","triggerScenarios":"File input change fired with no files selected; FileReader resolved with empty text (0-byte file); or the sniffing conditions are bypassed by an unexpected state (name without .csv and text containing 'BEGIN:VCARD' still goes to vcfParts, so the guard is near-unreachable).","commonSituations":"Selecting an empty (0-byte) file; programmatic clearing of the input then dispatching change; edge-case browser behavior where reader results are empty strings.","solutions":["Confirm the selected file is non-empty and is a real .vcf/.csv","Re-pick the file and retry the import","Validate file size > 0 before reading, and early-return when no files are selected","Move the no-data check before the POSTs (it already is) and warn earlier, at file-selection time"],"exampleFix":"// before\n        if (!vcfParts.length && !csvParts.length) throw new Error('No contact data found');\n\n// after\n        if (!e.target.files || !e.target.files.length) return; // nothing selected\n        if (!vcfParts.length && !csvParts.length) throw new Error('No contact data found — file appears empty');","handlingStrategy":"validation","validationCode":"const files = Array.from(e.target.files || []);\nif (!files.length) return;\nfor (const f of files) {\n  if (f.size === 0) { uiModule.showError(`\"${f.name}\" is empty`); return; }\n}\nconst looksVcf = t => String(t || '').toUpperCase().includes('BEGIN:VCARD');\nconst looksCsv = (name, t) => name.endsWith('.csv') || !looksVcf(t);","typeGuard":"function hasContactData(text) { return /BEGIN:VCARD/i.test(text) || /.+,.+/s.test(text); }","tryCatchPattern":"try { ... if (!vcfParts.length && !csvParts.length) throw new Error('No contact data found — file appears empty'); } catch (err) { (uiModule.showError || alert)(err?.message || 'Import failed'); }","preventionTips":["Reject 0-byte files at selection time","Early-return when no files are chosen","Confirm the extension matches the content (.csv vs .vcf)","Keep the empty check before any POST fires (already the case)"],"tags":["contacts","import","file-handling","validation"],"backgroundTag":null,"analyzedSha":"f9235ebbf13f693a6fd29ce70b097f6ec83705bf","analyzedAt":"2026-08-14T21:47:48.359Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}