santifer/career-ops · error · Error
--${name} must not contain tabs or newlines
Error message
--${name} must not contain tabs or newlines What it means
Validation in the `req`/`opt` helpers of `buildRow`: no field value may contain a tab (`\t`) or newline (`\n`). Because the log is a TSV (tab-separated, one row per line), a stray tab or newline would corrupt the column structure or split a single logical row into many. Both required and optional fields are checked.
Source
Thrown at assessment-log.mjs:119
staleFlagged,
withoutScore: rows.filter(r => r.score === null).length,
withoutThreshold: rows.filter(r => r.threshold === null).length,
malformedLines: malformed,
},
};
}
// --- Append (`add` subcommand) ---
export function buildRow(fields, today) {
const req = (name) => {
const v = String(fields[name] ?? '').trim();
if (!v) throw new Error(`--${name} is required`);
if (v.includes('\t') || v.includes('\n')) throw new Error(`--${name} must not contain tabs or newlines`);
return v;
};
const opt = (name) => {
const v = String(fields[name] ?? '').trim();
if (v.includes('\t') || v.includes('\n')) throw new Error(`--${name} must not contain tabs or newlines`);
return v || '-';
};
const optPct = (name) => {
const v = String(fields[name] ?? '').trim();
if (!v) return '-';
if (parsePct(v) === null) throw new Error(`--${name} must be a percentage (e.g. 70 or 70%), got "${v}"`);
return v;
};
return [
today, req('company'), opt('report'), req('platform'), req('subject'),
optPct('threshold'), optPct('score'), opt('stale') === '-' ? '' : opt('stale'),
].join('\t');
}
function addEntry(args) {
const fields = {};
for (let i = 0; i < args.length; i++) {
const m = args[i].match(/^--(company|report|platform|subject|threshold|score|stale)$/);View on GitHub (pinned to 9b17a8ac97)
Solutions
- Strip/replace tabs and newlines in each value before invoking: `value.replace(/[\t\r\n]+/g, ' ')`.
- Keep assessment-log fields single-line by design — put long-form notes in a different artifact.
- Quote/escape at the shell level (`$'...'`) only if you intend spaces, but never feed real tabs.
- Validate in your caller: `if (/[\t\n]/.test(v)) throw ...`.
- Add a test asserting values containing tab/newline are rejected.
Example fix
// before fields.company = 'Acme\tInc'; // throws // after fields.company = 'Acme\tInc'.replace(/[\t\n]+/g, ' '); // 'Acme Inc'
Defensive patterns
Strategy: validation
Validate before calling
function sanitizeTsv(v) {
const s = String(v ?? '');
if (/[
]/.test(s)) throw new Error('Field contains tab or newline');
return s.trim();
}
// or, to coerce rather than reject:
const clean = v.replace(/[
]+/g, ' '); Type guard
function isTsvSafe(v) {
const s = String(v ?? '');
return !/[
]/.test(s);
} Prevention
- Strip tabs/newlines from any pasted or model-generated value before invoking.
- Keep assessment-log fields single-line by design.
- Sanitize at the input boundary, not at TSV-write time.
- Test that embedded tabs/newlines are rejected.
When it happens
Trigger: Passing `--company 'Acme\tInc'`, `--subject 'arrays\nsorting'`, or any value containing literal tab/newline characters; copying multi-line text from a clipboard; programmatically injecting user-typed free text that contains line breaks.
Common situations: Pasted values from spreadsheets that embed tabs; multiline notes accidentally routed to a single-line field; agent generating values from a model that emits formatted text with line breaks; CSV-to-TSV conversion preserving embedded newlines.
Related errors
- --${name} is required
- --${name} must be a percentage (e.g. 70 or 70%), got "${v}"
- Application answer state must be one of: ${[...VALID_STATES]
- Missing value for ${arg}
- payload must include at least one of: cv, articleDigest
AI-assisted analysis of santifer/career-ops@9b17a8ac97 (2026-08-13).
Data as JSON: /api/errors/c7712a7842b0a76c.
Report an issue: GitHub.