santifer/career-ops · warning

Sync check could not run: ${err.message}

Error message

Sync check could not run: ${err.message}

What it means

verify-pipeline.mjs's health check 13 delegates to tracker-sync-check.mjs's exported checkTrackerSync(); that call threw before producing a result. In practice this means its inputs — data/applications.md and data/active-interviews.md — are missing or do not contain the expected markdown tables (never created, renamed, or emptied by a bad merge). The rest of verify-pipeline still runs; you just get no drift report for this check.

Source

Thrown at verify-pipeline.mjs:446

for (const [num, group] of numGroups) {
  if (group.length > 1) {
    error(`Duplicate tracker number #${num} used by ${group.length} rows: ${group.map(e => `${e.company} — ${e.role}`).join(' | ')}`);
    dupeNums++;
  }
}
if (dupeNums === 0) ok('No duplicate tracker numbers');

// --- Check 13: applications.md <-> active-interviews.md status sync (#1504) ---
// Delegates to tracker-sync-check.mjs's exported checkTrackerSync() rather than
// re-implementing the matching/two-tier resolution logic here or shelling out
// to a second process. Read-only: this only surfaces drift, it does not write
// a fix (tracker-sync-check.mjs is intentionally reporting-only for now — see
// its module header).
let syncResult;
try {
  syncResult = checkTrackerSync({ appsFile: APPS_FILE });
} catch (err) {
  warn(`Sync check could not run: ${err.message}`);
}

if (syncResult) {
  const tier1Mismatches = syncResult.mismatches.filter(m => m.resolution === 'auto-tier1');
  const tier2Mismatches = syncResult.mismatches.filter(m => m.resolution === 'needs-review-tier2');
  const unmatchedRows = syncResult.mismatches.filter(m => m.resolution === 'unmatched');

  for (const m of tier1Mismatches) {
    warn(`Sync drift (auto-resolvable): ${m.company} — ${m.role}: applications.md="${m.applicationsStatus}" vs active-interviews.md="${m.activeInterviewsStatus}" -> suggest "${m.suggestedStatus}" in ${m.staleIn} (run node tracker-sync-check.mjs for details)`);
  }
  for (const m of tier2Mismatches) {
    warn(`Sync drift (needs human review): ${m.company} — ${m.role}: applications.md="${m.applicationsStatus}" (${m.applicationsLastModified || 'no blame info'}) vs active-interviews.md="${m.activeInterviewsStatus}" (${m.activeInterviewsLastModified || 'no blame info'})`);
  }
  for (const m of unmatchedRows) {
    warn(`Sync check: active-interviews.md row for "${m.company}" — "${m.role}" could not be matched to a tracker row (${m.note})`);
  }
  if (tier1Mismatches.length === 0 && tier2Mismatches.length === 0 && unmatchedRows.length === 0) {
    ok(syncResult.summary.total > 0

View on GitHub (pinned to 60398d6549)

Solutions

  1. Run node tracker-sync-check.mjs standalone — its direct error pinpoints the file it choked on.
  2. Ensure data/active-interviews.md exists with the documented table header; same for data/applications.md.
  3. Re-run node verify-pipeline.mjs and confirm check 13 now reports instead of warning.

Example fix

# before — checkTrackerSync throws because active-interviews.md is missing
# after — create the file with the expected header, then re-run
cat > data/active-interviews.md <<'EOF'
# Active Interviews

| Company | Role | Round | Status | Last Update | Notes |
|---------|------|-------|--------|-------------|-------|
EOF
node verify-pipeline.mjs
Defensive patterns

Strategy: validation

Validate before calling

import { existsSync, readFileSync } from 'node:fs';
const tableReady = (p) => existsSync(p) && /^\|.*\|/m.test(readFileSync(p, 'utf-8'));
if (!tableReady('data/applications.md') || !tableReady('data/active-interviews.md')) {
  console.warn('sync-check inputs missing or unparsed — run node tracker-sync-check.mjs for details');
}

Try / catch

try {
  syncResult = checkTrackerSync({ appsFile: APPS_FILE });
} catch (err) {
  warn(`Sync check could not run: ${err.message}`);
} // degrade a single check, never the whole health report

Prevention

When it happens

Trigger: data/active-interviews.md absent (fresh install with no interviews tracked yet); the file exists but has no table header to parse; a tracker file renamed during reorganization; a conflict resolved by emptying the file.

Common situations: New setups before any interview tracking; repo reorganizations renaming tracker files; merge conflicts resolved by truncation.

Related errors


AI-assisted analysis of santifer/career-ops@60398d6549 (2026-08-20). Data as JSON: /api/errors/94dff5cb757f4633. Report an issue: GitHub.