odysseus-dev/odysseus · warning · Error
No contact data found
Error message
No contact data found
What it means
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.
Source
Thrown at static/js/settings.js:4169
if (name.endsWith('.csv') || !String(text || '').toUpperCase().includes('BEGIN:VCARD')) csvParts.push(text);
else vcfParts.push(text);
});
let imported = 0, total = 0, failed = 0;
const _postImport = async (body) => {
const r = await fetch('/api/contacts/import', {
method: 'POST', credentials: 'same-origin',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(body),
});
const d = await r.json();
if (d.error) throw new Error(d.error);
imported += Number(d.imported || 0);
total += Number(d.total || 0);
failed += Number(d.failed || 0);
};
if (vcfParts.length) await _postImport({ vcf: vcfParts.join('\n') });
if (csvParts.length) await _postImport({ csv: csvParts.join('\n') });
if (!vcfParts.length && !csvParts.length) throw new Error('No contact data found');
const msg = `Imported ${imported}/${total}` + (failed ? ` (${failed} failed)` : '');
uiModule.showToast ? uiModule.showToast(msg) : null;
} catch (err) {
uiModule.showError ? uiModule.showError(err?.message || 'Import failed') : alert(err?.message || 'Import failed');
} finally {
if (btn) { btn.textContent = orig; btn.disabled = false; }
e.target.value = '';
await _renderContactsManager();
}
});
await _renderContactsManager();
}
// Render the contacts list inside the manager card with inline edit +
// delete. Each row: name + emails; pencil flips to editable inputs.
async function _renderContactsManager() {
const list = el('cm-list');
if (!list) return;View on GitHub (pinned to f9235ebbf1)
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
Example fix
// before
if (!vcfParts.length && !csvParts.length) throw new Error('No contact data found');
// after
if (!e.target.files || !e.target.files.length) return; // nothing selected
if (!vcfParts.length && !csvParts.length) throw new Error('No contact data found — file appears empty'); Defensive patterns
Strategy: validation
Validate before calling
const files = Array.from(e.target.files || []);
if (!files.length) return;
for (const f of files) {
if (f.size === 0) { uiModule.showError(`"${f.name}" is empty`); return; }
}
const looksVcf = t => String(t || '').toUpperCase().includes('BEGIN:VCARD');
const looksCsv = (name, t) => name.endsWith('.csv') || !looksVcf(t); Type guard
function hasContactData(text) { return /BEGIN:VCARD/i.test(text) || /.+,.+/s.test(text); } Try / catch
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'); } Prevention
- 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)
When it happens
Trigger: 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).
Common situations: Selecting an empty (0-byte) file; programmatic clearing of the input then dispatching change; edge-case browser behavior where reader results are empty strings.
Related errors
- Import failed
- Invalid JSON
- Expected a JSON object
- d && d.detail ? d.detail : ('HTTP ' + res.status)
- result.detail || 'Failed to rename session'
AI-assisted analysis of odysseus-dev/odysseus@f9235ebbf1 (2026-08-14).
Data as JSON: /api/errors/1cc33b47012b98c7.
Report an issue: GitHub.