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
- Create/initialize the tracker at data/applications.md (or run the onboarding step that creates it).
- Verify the resolved path in the error message exists: ls <trackerPath>.
- If passing options.trackerPath, use an absolute path or ensure the cwd is the repository root.
- 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
- Initialize the tracker during onboarding before any follow-up automation runs.
- Use absolute paths for options.trackerPath, or always run from the repository root.
- Check whether CAREER_OPS_TRACKER / .career-ops-data redirect the path on this machine.
- Remember data/ may be gitignored — a fresh clone will not have it.
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
- ⚠️ not found at
- a16z-speedrun-talent: invalid URL
- agentic-jobs: invalid URL
- apify: JD cache write failed for
- cannot read
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)