santifer/career-ops · warning

⚠️ Skipping ${filename}: ambiguous extra fields [${extras.j

Error message

⚠️  Skipping ${filename}: ambiguous extra fields [${extras.join(', ')}] — expected at most one "via=Firm" tag, one location and one URL

What it means

parseTsvExtras() in merge-tracker.mjs classifies every field after the ninth column by shape: at most one `via=Firm` tag, at most one URL (http(s):// prefix), at most one untagged location. Any other combination — multiple via tags, multiple locations, multiple URLs, or other stray text — is ambiguous, so the whole file is skipped rather than guessed at.

Source

Thrown at merge-tracker.mjs:636

function parseTsvExtras(parts, filename) {
  // Drop placeholders outright. A generator emitting the documented trailing
  // `url` field for a posting that has none writes "N/A"/"TBD"/"—", and by shape
  // that is not a URL — it would fall into the untagged bucket and be recorded
  // as the row's LOCATION. An absent value must read as absent, not as some
  // other column's content.
  const PLACEHOLDER = /^(n\/?a|tbd|none|null|-|—|–)$/i;
  const extras = parts.slice(9)
    .map(s => String(s).trim())
    .filter(s => s !== '' && !PLACEHOLDER.test(s));
  const viaTags = extras.filter(s => /^via=/i.test(s));
  // Classify trailing fields by SHAPE, not position. A URL is
  // unambiguous (starts with http(s)://), so the posting URL and an older
  // location cell are order-independent and a row carrying both is not read as
  // two ambiguous locations. Location-only rows keep working untouched.
  const urls = extras.filter(s => !/^via=/i.test(s) && /^https?:\/\//i.test(s));
  const untagged = extras.filter(s => !/^via=/i.test(s) && !/^https?:\/\//i.test(s));
  if (viaTags.length > 1 || untagged.length > 1 || urls.length > 1) {
    console.warn(`⚠️  Skipping ${filename}: ambiguous extra fields [${extras.join(', ')}] — expected at most one "via=Firm" tag, one location and one URL`);
    return null;
  }
  return {
    via: viaTags.length ? viaTags[0].replace(/^via=/i, '').trim() : '',
    location: untagged[0] || '',
    url: urls[0] || '',
  };
}

function parseTsvContent(content, filename) {
  content = content.trim();
  if (!content) return null;

  let parts;
  let addition;

  // Detect pipe-delimited (markdown table row)
  if (content.startsWith('|')) {

View on GitHub (pinned to 60398d6549)

Solutions

  1. Reduce extras to at most one via= tag, one location, and one URL per row
  2. Move additional commentary into the notes column (field 9) instead of appending new columns
  3. Ensure the file is genuine tab-separated with no stray tabs inside notes

Example fix

# before
042	2026-08-20	Acme	SRE	Interview	4.2/5	✅	[042](reports/042-acme-2026-08-20.md)	note	via=Hays	via=Adecco

# after
042	2026-08-20	Acme	SRE	Interview	4.2/5	✅	[042](reports/042-acme-2026-08-20.md)	note	via=Hays
Defensive patterns

Strategy: validation

Validate before calling

function extrasAreUnambiguous(parts) {
  const PLACEHOLDER = /^(n\/?a|tbd|none|null|-|—|–)$/i;
  const extras = parts.slice(9).map(s => s.trim()).filter(s => s !== '' && !PLACEHOLDER.test(s));
  const count = re => extras.filter(re).length;
  return count(/^via=/i) <= 1 && count(/^https?:\/\//i) <= 1 &&
         count(s => !/^via=/i.test(s) && !/^https?:\/\//i.test(s)) <= 1;
}

Prevention

When it happens

Trigger: A TSV row appending e.g. `...notes via=Hays via=Adecco` or `...notes Berlin Remote` — viaTags.length > 1 or untagged.length > 1 trips the guard, the warning names the offending fields, and parseTsvContent returns null so the addition is skipped.

Common situations: Hand-extended rows adding both a location and a comment; concatenating two TSV exports whose extra columns differ; a note containing tab characters splitting into phantom fields.

Related errors


AI-assisted analysis of santifer/career-ops@60398d6549 (2026-08-20). Data as JSON: /api/errors/d2aab5bbef4c1375. Report an issue: GitHub.