santifer/career-ops · error · Error

-- must not contain tabs or newlines

Error message

--${name} must not contain tabs or newlines

What it means

In buildRow(), req() validates required fields and rejects any value containing a tab or newline character. assessments.tsv is a tab-delimited append-only file, so an embedded \t or \n would shift or break the row's column structure. The library fails fast rather than writing a corrupt row.

Solutions

  1. Remove tabs/newlines from the offending value and re-run the command (replace with a space).
  2. Sanitize with tr: `--subject "$(echo "$SUBJECT" | tr '\t\n' ' ')"`.
  3. If calling buildRow() programmatically, pre-clean the value: v.replace(/[\t\n]/g, ' ').trim().
  4. Use a shell single-line string and verify with `echo "$VALUE" | cat -A` if unsure where the invisible character is.

Example fix

// before
buildRow({ company: "Acme\nHoldings", platform: "codesignal", subject: "algo" }, today)
// Error: --company must not contain tabs or newlines
// after
buildRow({ company: "Acme Holdings", platform: "codesignal", subject: "algo" }, today)
Defensive patterns

Strategy: validation

Validate before calling

function isTsvSafe(v) { return !/[\t\n]/.test(String(v).trim()); }
// check all values before calling buildRow
if (!Object.values(fields).every(isTsvSafe)) throw new Error('values must not contain tabs or newlines');

Type guard

const isTsvSafe = (v) => typeof v === 'string' && !/[\t\n]/.test(v.trim());

Try / catch

try {
  const row = buildRow(fields, today);
} catch (err) {
  if (err.message.includes('must not contain tabs or newlines')) {
    const flag = err.message.split(' ')[0].replace('--', '');
    fields[flag] = String(fields[flag]).replace(/[\t\n]/g, ' ').trim();
    return buildRow(fields, today); // retry with sanitized value
  }
  throw err;
}

Prevention

When it happens

Trigger: Calling buildRow() with a required field (company, platform, subject) whose trimmed value contains '\t' or '\n' — e.g. pasting a multi-line company name, a subject copied from a PDF with a line break, or an argument that literally contains tab characters.

Common situations: Copying a course or platform name from a website/Slack that carries a trailing newline; shell command substitution `--subject "$(cat notes.txt)"` pulling in line breaks; editors inserting tabs; programmatic callers passing unsanitized user input.

Understand the failure class

Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.

Related errors


AI-assisted analysis of santifer/career-ops@aac998c7ed (2026-09-16). Data as JSON: /api/errors/c7712a7842b0a76c. Report an issue: GitHub.

Appendix: source

Thrown at assessment-log.mjs:127

  return {
    assessments: rows,
    aggregates: { byPlatform },
    quality: {
      total: rows.length,
      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');
}

View on GitHub (pinned to aac998c7ed)