santifer/career-ops · warning · SeedError

NOT_APPLIED

NOT_APPLIED

Error message

Application #${appNum} is not Applied (status: "${row.status.trim()}"); use --force to seed anyway

What it means

The row was found but its status does not normalize to 'applied'. Follow-up seeding only makes sense for Applied rows because the cadence clock starts at application submission (applied_first offset from resolveAppliedDate). Thrown only when options.force is falsy. normalizeStatus handles lowercase, trailing dates, localized variants, and markdown bold.

Source

Thrown at followup-seed.mjs:435

  if (options.date != null && !isValidCalendarDate(options.date)) {
    throw new SeedError('INVALID_DATE', `--date must be a real calendar date in YYYY-MM-DD form: ${options.date}`);
  }

  const trackerPath = resolveTrackerPath(options.trackerPath);
  const followupsPath = resolveFollowupsPath(options.followupsPath);

  if (!existsSync(trackerPath)) {
    throw new SeedError('ROW_NOT_FOUND', `Tracker not found at ${trackerPath}`);
  }
  const rows = readTrackerRows(trackerPath);
  const row = rows.find(r => r.num === appNum);
  if (!row) {
    throw new SeedError('ROW_NOT_FOUND', `Application #${appNum} not found in ${trackerPath}`);
  }

  const normalized = normalizeStatus(row.status);
  if (normalized !== 'applied' && !options.force) {
    throw new SeedError('NOT_APPLIED', `Application #${appNum} is not Applied (status: "${row.status.trim()}"); use --force to seed anyway`);
  }

  const appliedDate = resolveAppliedDate(row, options.date);
  const cadence = resolveCadenceConfig({ profilePath: options.profilePath });
  const nextDate = addDays(parseDate(appliedDate), cadence.applied_first);
  const setDate = todayStr();
  const pin = formatPinLine(appNum, nextDate, setDate);

  if (options.dryRun) {
    const existingContent = existsSync(followupsPath) ? readFileSync(followupsPath, 'utf-8') : '';
    if (isAlreadySeeded(existingContent, appNum) && !options.force) {
      return { seeded: false, appNum, pin: null, nextDate, appliedDate, setDate, reason: 'already-seeded', dryRun: true };
    }
    return { seeded: true, appNum, pin, nextDate, appliedDate, setDate, dryRun: true };
  }

  const lockDir = resolveLockDir(options.lockDir, followupsPath);
  const lock = await acquireFollowupsLock(lockDir, followupsPath, {

View on GitHub (pinned to 9b17a8ac97)

Solutions

  1. Mark the row Applied first: node set-status.mjs <appNum> Applied, then seed.
  2. If you genuinely want to seed regardless of status, pass --force (or options.force: true).

Example fix

// before
await seedFollowup(42);
// throws: Application #42 is not Applied (status: "Evaluated")

// after — option 1: mark Applied first
// node set-status.mjs 42 Applied
await seedFollowup(42);

// after — option 2: force seed
await seedFollowup(42, { force: true });
Defensive patterns

Strategy: validation

Validate before calling

import { normalizeStatus } from './followup-cadence.mjs';

const normalized = normalizeStatus(row.status);
if (normalized !== 'applied') {
  // Option A: mark Applied first via set-status.mjs
  // Option B: pass force: true if you understand the implication
  throw new Error(`Row is ${row.status}, not Applied. Mark Applied or use --force.`);
}

Try / catch

try {
  await seedFollowup(appNum);
} catch (err) {
  if (err.code === 'NOT_APPLIED') {
    console.error(err.message);
    // Decide: mark Applied, or force seed
    // await seedFollowup(appNum, { force: true });
    process.exit(1);
  }
  throw err;
}

Prevention

When it happens

Trigger: Row status is 'Evaluated', 'Responded', 'Interview', 'Rejected', 'Discarded', or 'Offer'; trying to seed before marking the row Applied; the row was Applied but was since advanced to Responded.

Common situations: User tries to seed a follow-up before running set-status.mjs to mark Applied; wanting to retroactively seed a row that is now in Interview; seeding after the row was rejected.

Related errors


AI-assisted analysis of santifer/career-ops@9b17a8ac97 (2026-08-13). Data as JSON: /api/errors/2b8f524cf0c425e2. Report an issue: GitHub.