santifer/career-ops · error

file not found: ${filePath}

Error message

file not found: ${filePath}

What it means

validate-portals.mjs's validateFile() runs existsSync() on the resolved config path and throws this before parsing when the file is absent. main() catches it, prints 'validate-portals failed: file not found: <path>' and exits 1. Note the empty-`--file=` guard: an explicitly empty flag value is turned into a usage error instead of resolving to the current directory.

Source

Thrown at validate-portals.mjs:277

        } else if (!providerIds.has(company.provider)) {
          add(errors, `${base}.provider`, `unknown provider "${company.provider}"`);
        }
      }

      validateParser(company.parser, `${base}.parser`, errors);
    }
  }

  return { errors, warnings };
}

function formatIssue(issue) {
  return `${issue.path}: ${issue.message}`;
}

async function validateFile(filePath) {
  if (!existsSync(filePath)) {
    throw new Error(`file not found: ${filePath}`);
  }
  const providerIds = await loadProviderIds();
  const parsed = yaml.load(readFileSync(filePath, 'utf-8'));
  return validatePortalsConfig(parsed, { providerIds });
}

async function runSelfTest() {
  const tmp = mkdtempSync(join(tmpdir(), 'career-ops-validate-portals-self-test-'));
  try {
    const file = join(tmp, 'bad.yml');
    writeFileSync(file, `
title_filter:
  positive: ["AI", ""]
tracked_companies:
  - name: "Acme"
    provider: "not-real"
    careers_url: "https://jobs.lever.co/acme"
`, 'utf-8');

View on GitHub (pinned to 60398d6549)

Solutions

  1. Confirm the file exists at the path printed in the message: `ls -l <path>`
  2. Run from the repo root, or pass an absolute path: `node validate-portals.mjs --file /abs/path/portals.yml`
  3. If portals.yml is missing, create it first: `cp templates/portals.example.yml portals.yml` then edit
  4. Check for typos in the --file value and remember the path resolves against process.cwd()

Example fix

# before (run from scripts/ subdir; portals.yml lives at repo root)
node ../validate-portals.mjs   # file not found: /repo/scripts/portals.yml
# after
node ../validate-portals.mjs --file /repo/portals.yml
Defensive patterns

Strategy: validation

Validate before calling

import { existsSync, realpathSync } from 'node:fs';
import { resolve } from 'node:path';
const p = resolve(process.cwd(), 'portals.yml');
if (!existsSync(p)) {
  console.error(`portals.yml missing at ${p}; copy templates/portals.example.yml first`);
  process.exit(1);
}

Try / catch

try {
  await validateFile(filePath);
} catch (err) {
  if (String(err.message).startsWith('file not found:')) {
    // path problem, not schema problem: fix the path, do not touch the config
    console.error('bad path, expected:', err.message);
    process.exit(1);
  }
  throw err;
}

Prevention

When it happens

Trigger: `node validate-portals.mjs` before onboarding has created portals.yml (DEFAULT_PORTALS_PATH is missing), or `--file <path>` with a typo'd/relative path resolved against the wrong cwd. Self-test writes its own temp file, so it never hits this.

Common situations: Fresh clone where portals.yml has not yet been copied from templates/portals.example.yml (Step 3 of onboarding); running the command from a subdirectory so the relative default path misses; CI validating a renamed config path.

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@60398d6549 (2026-08-20). Data as JSON: /api/errors/1eaf0f7298c24e8e. Report an issue: GitHub.