santifer/career-ops · critical
tracker-parse.mjs: cannot load tracker-aliases.json
Error message
tracker-parse.mjs: cannot load tracker-aliases.json (${e.message}). The file ships with career-ops next to tracker-parse.mjs — restore it from the repo or re-run: node update-system.mjs apply What it means
tracker-parse.mjs loads its alias table (HEADER_ALIASES) from tracker-aliases.json at module init via an import.meta.url-relative readFileSync. If that JSON is missing or unreadable, the module cannot map tracker column names, so it throws immediately at import time instead of failing later on a mis-parsed tracker. The file ships with career-ops next to tracker-parse.mjs.
Solutions
- Run `node update-system.mjs apply` to restore shipped system files including tracker-aliases.json
- Restore tracker-aliases.json from the career-ops repo (git checkout -- tracker-aliases.json or re-download next to tracker-parse.mjs)
- Check file permissions on tracker-aliases.json (readable by the running user)
- Verify the file parses as JSON (node -e "JSON.parse(require('fs').readFileSync('tracker-aliases.json','utf-8'))") to rule out truncation/corruption
Example fix
// before cp tracker-parse.mjs ~/tools/ # copied script without its JSON companion -> throws at import // after cp tracker-parse.mjs tracker-aliases.json ~/tools/ # keep both files together
Defensive patterns
Strategy: fallback
Validate before calling
import { existsSync } from 'fs';
if (!existsSync(new URL('./tracker-aliases.json', import.meta.url))) {
throw new Error('tracker-aliases.json missing; run: node update-system.mjs apply');
} Type guard
const isAliasFileOk = (dir) => existsSync(join(dir, 'tracker-aliases.json'));
Try / catch
try {
const { HEADER_ALIASES } = await import('./tracker-parse.mjs');
} catch (e) {
if (String(e.message).includes('tracker-aliases.json')) {
// restore shipped files then re-import
}
} Prevention
- Keep tracker-parse.mjs and tracker-aliases.json together when copying or bundling
- Run node doctor.mjs / update-system.mjs check after pulling system updates
- Include .json assets in packaging/bundle configuration
- Verify repo checkout completeness with git status after clone/sync
When it happens
Trigger: Any import/require of tracker-parse.mjs when tracker-aliases.json is absent from the module directory, was deleted, or cannot be read (permissions, partial update checkout, packaging that dropped JSON assets).
Common situations: Partial git checkout or sparse clone that skipped JSON files; a system update that replaced tracker-parse.mjs but not its companion data file; copying the .mjs file alone to another location; npm/packaging rules that exclude .json siblings; restrictive file permissions after running as another user.
Related errors
- must be an array in
- apify: entry has invalid field_map. Each of title, url…
- apify: entry missing 'actor' (e.g. misceres/indeed-scraper)
- APIFY_TOKEN not set — enable apify in config/plugins.yml…
- arbeitnow: invalid URL
AI-assisted analysis of santifer/career-ops@aac998c7ed (2026-09-16).
Data as JSON: /api/errors/5ad05eafdb67eb8c.
Report an issue: GitHub.
Appendix: source
Thrown at tracker-parse.mjs:40
/**
* Header text (lowercased) → canonical field name. Includes ES aliases.
* Loaded from tracker-aliases.json — the ONE shared alias table, which the web
* read path (web/src/lib/tracker-table.mjs) also loads at runtime, so the two
* can never drift (PR #1598 review). Add new aliases in the JSON, not here.
*
* A missing or corrupt JSON is a broken install (the file ships alongside this
* module in SYSTEM_PATHS/BOOTSTRAP_PATHS): fail fast with an actionable
* message rather than degrading silently — a quiet fallback here would
* reintroduce exactly the reader drift the shared table exists to prevent.
* (The web loader degrades to the legacy fixed order instead because it reads
* the file from a user-configured root at request time.)
*/
export const HEADER_ALIASES = (() => {
const src = new URL('./tracker-aliases.json', import.meta.url);
try {
return JSON.parse(readFileSync(src, 'utf-8'));
} catch (e) {
throw new Error(
`tracker-parse.mjs: cannot load tracker-aliases.json (${e.message}). ` +
'The file ships with career-ops next to tracker-parse.mjs — restore it ' +
'from the repo or re-run: node update-system.mjs apply',
);
}
})();
/**
* A score cell in the tracker: `N/5` or `N.N/5` (any precision), or the
* sentinels `N/A` / `DUP` / `—` (em dash) / `-` (hyphen). Markdown bold is
* stripped first. `—`/`-` mirror the tracker's own "no data" convention used
* in every other column (Report, PDF, etc.) — see #1799: a backfilled entry
* with no evaluation (e.g. a rejection for a role never run through
* `oferta`) needs a score-cell sentinel too, not just `N/A`. A status label
* never matches this, which is what makes it a reliable discriminator between
* the score and status columns regardless of their order (#1427).
*/
export const SCORE_CELL_RE = /^\d+(?:\.\d+)?\/5$/;View on GitHub (pinned to aac998c7ed)