santifer/career-ops · error · SeedError

INVALID_DATE

INVALID_DATE

Error message

Application #${row?.num ?? '?'} notes carry an impossible "Applied ${notesDate}" date; fix the notes or pass --date

What it means

resolveAppliedDate derives an application's Applied date for seeding the first follow-up: from an explicit --date, else from an 'Applied YYYY-MM-DD' pattern in the tracker row's notes, else from the row's date cell. When the notes contain an Applied date string that parses but is not a valid calendar date (e.g. 2026-02-30, month 13), it throws a SeedError with code INVALID_DATE rather than pinning a nonsense follow-up date.

Solutions

  1. Fix the notes column of the named application row so the 'Applied <date>' value is a real calendar date, then re-run.
  2. Pass an explicit --date YYYY-MM-DD to override the notes value for this run.
  3. If the date cell (not the notes) is the intended source, remove the bogus 'Applied ...' text from notes so resolution falls through to the date cell.
  4. Update via node set-status.mjs <row> <State> --note ... to rewrite notes through the canonical path instead of hand-editing the table.
  5. Add a date sanity check to any script that writes 'Applied' notes to prevent recurrence.

Example fix

// before: tracker row notes
| 42 | 2025-09-01 | Acme | Backend | — | Applied | ❌ | [42](reports/042-acme.md) | Applied 2025-02-30, emailed recruiter | //

// after: corrected notes (2025-02-28)
| 42 | 2025-09-01 | Acme | Backend | — | Applied | ❌ | [42](reports/042-acme.md) | Applied 2025-02-28, emailed recruiter |
Defensive patterns

Strategy: validation

Validate before calling

function isRealCalendarDate(s) {
  const m = /^(\d{4})-(\d{2})-(\d{2})$/.exec(s ?? '');
  if (!m) return false;
  const d = new Date(Date.UTC(+m[1], +m[2] - 1, +m[3]));
  return d.getUTCFullYear() === +m[1] && d.getUTCMonth() === +m[2] - 1 && d.getUTCDate() === +m[3];
}
// check notes for /Applied (\d{4}-\d{2}-\d{2})/ and run isRealCalendarDate before seeding

Try / catch

try {
  const { appliedDate } = resolveAppliedDate(row, cliDate);
} catch (err) {
  if (err.code === 'INVALID_DATE') {
    console.error(`${err.message}\nFix the row's notes or pass --date YYYY-MM-DD`);
    process.exit(1);
  }
  throw err;
}

Prevention

When it happens

Trigger: Running followup-seed (or a mode that seeds follow-ups) without --date on a tracker row whose notes contain something like 'Applied 2025-02-30' or 'Applied 2025-13-01' — a syntactically date-like but calendar-impossible value that parseAppliedDate extracts and isValidCalendarDate rejects.

Common situations: Typo when hand-writing notes ('Applied 2025-04-31'); swapped day/month after converting from US format (2025-04-13 vs 13th month); row duplicated with an edited but broken date; notes written by a script with an unvalidated computed date.

Related errors


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

Appendix: source

Thrown at followup-seed.mjs:177

 * `today` remains the last resort for a row whose `date` column is missing or
 * unusable — but it is now labelled too, rather than being indistinguishable
 * from a measured date.
 *
 * A notes date that isn't a real calendar date (e.g. "Applied 2026-02-31")
 * throws rather than falling through: `parseDate` would return null for it and
 * the pin would be written with a literal "null" next-date.
 *
 * @param {{num?: number, notes?: string, date?: string}} row - Parsed tracker row.
 * @param {string|null|undefined} explicitDate - `--date` value, already validated.
 * @returns {{appliedDate: string, appDateSource: 'explicit'|'notes'|'evaluation-date'|'today'}}
 * @throws {SeedError} INVALID_DATE when the notes carry an impossible date.
 */
export function resolveAppliedDate(row, explicitDate) {
  if (explicitDate) return { appliedDate: explicitDate, appDateSource: 'explicit' };
  const notesDate = parseAppliedDate(row?.notes);
  if (notesDate) {
    if (!isValidCalendarDate(notesDate)) {
      throw new SeedError('INVALID_DATE', `Application #${row?.num ?? '?'} notes carry an impossible "Applied ${notesDate}" date; fix the notes or pass --date`);
    }
    return { appliedDate: notesDate, appDateSource: 'notes' };
  }
  // Only a usable calendar date qualifies: a blank or malformed `date` cell
  // must not become a pin with a "null" next-date, which is the same failure
  // the notes branch throws over.
  const columnDate = String(row?.date ?? '').trim();
  if (isValidCalendarDate(columnDate)) {
    return { appliedDate: columnDate, appDateSource: 'evaluation-date' };
  }
  return { appliedDate: todayStr(), appDateSource: 'today' };
}

/**
 * Format one pin directive line. The parser side lives in
 * followup-cadence.mjs's `OVERRIDE_RE` / `parseNextOverrides`.
 *
 * @param {number} appNum

View on GitHub (pinned to aac998c7ed)