santifer/career-ops · warning
⚠️ Skipping : data row has field(s), missing the required…
Error message
⚠️ Skipping ${filename}: data row has ${parts.length} field(s), missing the required cell(s): ${missingRequiredCells.join(', ')} What it means
In a headed TSV, every required field (num, date, company, role, score, status, pdf, report) must have a cell present in the data row. If the row is shorter than a required label's column index, the parser cannot map the row onto the header and skips the file. Optional trailing cells may be absent (absent and empty read the same), but a short row that cuts off a REQUIRED cell is rejected; an interior omission that shifts values is caught separately by the score corroboration.
Solutions
- Count the tab-separated cells in the data row against the header labels and append the missing required cell(s) named in the warning, in header order.
- Use the documented sentinels where a value genuinely doesn't exist: '—' or 'N/A' for score, '—' for report, '❌' for pdf.
- Ensure the file is tab-delimited, not comma- or space-delimited; re-save with real tabs if an editor converted them.
- Fix the emitter template so it always writes one tab per header label, even when a value is empty.
Example fix
// before (row stops after role — score/status/pdf/report missing) num date company role score status pdf report 42 2026-09-16 Acme Backend Engineer // after num date company role score status pdf report 42 2026-09-16 Acme Backend Engineer 4.2/5 Evaluated ❌ [042](reports/042.md)
Defensive patterns
Strategy: validation
Validate before calling
const REQUIRED = ['num','date','company','role','score','status','pdf','report'];
const header = lines[0].split('\t');
const cells = lines[1].split('\t');
const missing = REQUIRED.filter(label => header.indexOf(label) >= cells.length);
if (missing.length) throw new Error(`${file}: data row missing required cell(s): ${missing.join(', ')}`); Prevention
- Emit exactly one tab per header label — build rows from the header array itself, not by hand.
- Never let a shell variable interpolation silently produce an empty cell; fail loudly on unset variables (set -u).
- Verify the file is tab-delimited after every editor save (spaces and commas are not cell separators here).
- Keep emitter templates and header labels in sync when adding columns.
When it happens
Trigger: parseHeadedAddition (merge-tracker.mjs:825) computes shortLabels = labels whose column index >= parts.length, filters to TSV_REQUIRED_FIELDS, and finds a non-empty set — i.e. splitAdditionCells(dataLines[0]) produced fewer tab-separated cells than the position of some required label.
Common situations: A writer emitted only 4-7 of the 8 required cells, stopping after notes; a template's header was edited to add a column but the data row wasn't updated; a shell script built the row with a failing variable leaving the tail empty; tabs were converted to spaces by an editor, collapsing cells.
Understand the failure class
Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.
Related errors
- ⚠️ Skipping : a URL sits under " " while the "url" cell is…
- ⚠️ Skipping : cannot tell score from status in columns 5–6…
- ⚠️ Skipping : data rows — one addition per file
- ⚠️ Skipping : header row with no data row
- ⚠️ Skipping : invalid entry number
AI-assisted analysis of santifer/career-ops@aac998c7ed (2026-09-16).
Data as JSON: /api/errors/68799f488687d703.
Report an issue: GitHub.
Appendix: source
Thrown at merge-tracker.mjs:826
return null;
}
const parts = splitAdditionCells(dataLines[0]);
// Only the REQUIRED cells must actually be there. A row whose trailing
// optional value is empty is routinely written without its final tab —
// openrouter-runner emits `…\treport\t\n` for an absent note, and an LLM
// writer asked for "leave the last field empty" often just stops — so
// demanding a cell for every label would reject canonical rows. Absent and
// empty read the same here, which is what the batch and web prompts already
// promise their writers.
//
// This is not the defense against a SHIFTED row: an omitted interior cell
// slides every later value one column left, which the score corroboration
// below catches by content regardless of the row's width.
const shortLabels = Object.entries(map).filter(([, i]) => i >= parts.length).map(([k]) => k);
const missingRequiredCells = shortLabels.filter(k => TSV_REQUIRED_FIELDS.includes(k));
if (missingRequiredCells.length) {
console.warn(`⚠️ Skipping ${filename}: data row has ${parts.length} field(s), missing the required cell(s): ${missingRequiredCells.join(', ')}`);
return null;
}
const at = (k) => (map[k] != null ? String(parts[map[k]] ?? '').trim() : '');
const optional = (k) => {
const v = at(k);
return PLACEHOLDER_CELL.test(v) ? '' : v;
};
// A required cell that is PRESENT but blank is a writer that did not supply
// the value, and blank is never the way to say "none" here: every required
// field has a documented value, and the "no data" cases have sentinels
// (`—` / `N/A` for score, `—` for report, `❌` for pdf). Left unchecked, an
// empty status reaches validateStatus(''), which warns and returns
// "Evaluated" — recording a real evaluation state the row never claimed.
const blankRequiredCells = TSV_REQUIRED_FIELDS.filter(k => at(k) === '');
if (blankRequiredCells.length) {
console.warn(`⚠️ Skipping ${filename}: required cell(s) present but empty: ${blankRequiredCells.join(', ')} — use the documented sentinel (— / N/A) rather than a blank cell`);View on GitHub (pinned to aac998c7ed)