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

  1. Confirm the selected file is non-empty and is a real .vcf/.csv
  2. Re-pick the file and retry the import
  3. Validate file size > 0 before reading, and early-return when no files are selected
  4. 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

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


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