{"record":{"id":"c7712a7842b0a76c","repo":"santifer/career-ops","slug":"name-must-not-contain-tabs-or-newlines","errorCode":null,"errorMessage":"--${name} must not contain tabs or newlines","messagePattern":"--(.+?) must not contain tabs or newlines","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"assessment-log.mjs","lineNumber":127,"sourceCode":"  return {\n    assessments: rows,\n    aggregates: { byPlatform },\n    quality: {\n      total: rows.length,\n      staleFlagged,\n      withoutScore: rows.filter(r => r.score === null).length,\n      withoutThreshold: rows.filter(r => r.threshold === null).length,\n      malformedLines: malformed,\n    },\n  };\n}\n\n// --- Append (`add` subcommand) ---\nexport function buildRow(fields, today) {\n  const req = (name) => {\n    const v = String(fields[name] ?? '').trim();\n    if (!v) throw new Error(`--${name} is required`);\n    if (v.includes('\\t') || v.includes('\\n')) throw new Error(`--${name} must not contain tabs or newlines`);\n    return v;\n  };\n  const opt = (name) => {\n    const v = String(fields[name] ?? '').trim();\n    if (v.includes('\\t') || v.includes('\\n')) throw new Error(`--${name} must not contain tabs or newlines`);\n    return v || '-';\n  };\n  const optPct = (name) => {\n    const v = String(fields[name] ?? '').trim();\n    if (!v) return '-';\n    if (parsePct(v) === null) throw new Error(`--${name} must be a percentage (e.g. 70 or 70%), got \"${v}\"`);\n    return v;\n  };\n  return [\n    today, req('company'), opt('report'), req('platform'), req('subject'),\n    optPct('threshold'), optPct('score'), opt('stale') === '-' ? '' : opt('stale'),\n  ].join('\\t');\n}","sourceCodeStart":109,"sourceCodeEnd":145,"githubUrl":"https://github.com/santifer/career-ops/blob/aac998c7ed7248ea853b720ceeb1fdbeb322fc5d/assessment-log.mjs#L109-L145","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Remove tabs/newlines from the offending value and re-run the command (replace with a space).","Sanitize with tr: `--subject \"$(echo \"$SUBJECT\" | tr '\\t\\n' '  ')\"`.","If calling buildRow() programmatically, pre-clean the value: v.replace(/[\\t\\n]/g, ' ').trim().","Use a shell single-line string and verify with `echo \"$VALUE\" | cat -A` if unsure where the invisible character is."],"exampleFix":"// before\nbuildRow({ company: \"Acme\\nHoldings\", platform: \"codesignal\", subject: \"algo\" }, today)\n// Error: --company must not contain tabs or newlines\n// after\nbuildRow({ company: \"Acme Holdings\", platform: \"codesignal\", subject: \"algo\" }, today)","handlingStrategy":"validation","validationCode":"function isTsvSafe(v) { return !/[\\t\\n]/.test(String(v).trim()); }\n// check all values before calling buildRow\nif (!Object.values(fields).every(isTsvSafe)) throw new Error('values must not contain tabs or newlines');","typeGuard":"const isTsvSafe = (v) => typeof v === 'string' && !/[\\t\\n]/.test(v.trim());","tryCatchPattern":"try {\n  const row = buildRow(fields, today);\n} catch (err) {\n  if (err.message.includes('must not contain tabs or newlines')) {\n    const flag = err.message.split(' ')[0].replace('--', '');\n    fields[flag] = String(fields[flag]).replace(/[\\t\\n]/g, ' ').trim();\n    return buildRow(fields, today); // retry with sanitized value\n  }\n  throw err;\n}","preventionTips":["Pipe pasted values through `tr '\\t\\n' '  '` before use.","Avoid `$(cat file)` substitution for flag values; read single-line values only.","Inspect suspicious values with `cat -A` to reveal hidden tabs/newlines.","Sanitize input centrally if you drive `add` from a script."],"tags":["cli","validation","tsv-format"],"backgroundTag":"invalid-argument-format","analyzedSha":"aac998c7ed7248ea853b720ceeb1fdbeb322fc5d","analyzedAt":"2026-09-16T06:35:29.214Z","contentChangedAt":"2026-09-16T06:35:29.214Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}