santifer/career-ops · error · SeedError

ROW_NOT_FOUND

ROW_NOT_FOUND

Error message

Tracker not found at ${trackerPath}

What it means

seedFollowup resolves the tracker path (explicit option or the canonical location: CAREER_OPS_TRACKER override, data/applications.md, falling back to applications.md) and checks it exists with existsSync before reading. If the tracker file itself is missing, it throws SeedError with code ROW_NOT_FOUND indicating the tracker file was not found at the resolved path. Note this code covers both 'file missing' and 'row missing' (see error 54).

Solutions

  1. Create/initialize the tracker at data/applications.md (or run the onboarding step that creates it).
  2. Verify the resolved path in the error message exists: ls <trackerPath>.
  3. If passing options.trackerPath, use an absolute path or ensure the cwd is the repository root.
  4. Check the CAREER_OPS_TRACKER environment variable for a wrong or stale value.

Example fix

// before
await seedFollowup(42, { trackerPath: 'data/trackers/application.md' }); // typo
// after — confirm the file exists first
const p = resolve('data/applications.md');
if (!existsSync(p)) throw new Error(`Tracker missing at ${p}; run onboarding first`);
await seedFollowup(42, { trackerPath: p });
Defensive patterns

Strategy: validation

Validate before calling

import { existsSync } from 'node:fs';
const trackerPath = options.trackerPath ?? resolve('data/applications.md');
if (!existsSync(trackerPath)) {
  throw new Error(`Tracker not found at ${trackerPath}; run career-ops onboarding first.`);
}

Try / catch

try {
  await seedFollowup(appNum);
} catch (e) {
  if (e.code === 'ROW_NOT_FOUND' && /Tracker not found/.test(e.message)) {
    console.error('Tracker file missing — initialize data/applications.md before seeding.');
    process.exitCode = 1;
  } else throw e;
}

Prevention

When it happens

Trigger: Running seedFollowup before the tracker was ever created (empty project / fresh clone); passing options.trackerPath pointing at a non-existent or misspelled file; a relative trackerPath resolved against a different working directory than expected; CAREER_OPS_TRACKER pointing to a path that does not exist.

Common situations: First run of the pipeline where data/ was not initialized; running the script from a different cwd in CI than locally; a data directory that was gitignored and therefore absent on a new machine; a typo'd override env var.

Understand the failure class

Background: "File not found" and ENOENT errors: why libraries can't find a file that should exist — this error's family across 50 libraries.

Related errors


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

Appendix: source

Thrown at followup-seed.mjs:555

    return await fn();
  } finally {
    lock.release();
  }
}

export async function seedFollowup(appNum, options = {}) {
  if (!Number.isInteger(appNum) || appNum <= 0) {
    throw new SeedError('USAGE', `Invalid appNum: ${appNum}`);
  }
  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 && !options.assumeApplied) {
    throw new SeedError('NOT_APPLIED', `Application #${appNum} is not Applied (status: "${row.status.trim()}"); use --force to seed anyway`);
  }

  // appDateSource travels with the result so a caller can tell a measured apply
  // date from a proxy or a guess — the same contract followup-cadence.mjs and
  // company-history.mjs already expose.
  const { appliedDate, appDateSource } = resolveAppliedDate(row, options.date);
  const cadence = resolveCadenceConfig({ profilePath: options.profilePath });
  const nextDate = addDays(parseDate(appliedDate), cadence.applied_first);

View on GitHub (pinned to aac998c7ed)