santifer/career-ops · error

${LOCAL_PATHS_FILE}: refusing "${path}" — ${why}

Error message

${LOCAL_PATHS_FILE}: refusing "${path}" — ${why}

What it means

config/local-paths.txt declares extra user-layer paths the auto-updater must never touch. localUserPaths() validates every declared entry and hard-refuses three shapes: absolute paths (POSIX leading / or Windows drive/backslash forms), paths containing a .. segment, and the file listing itself (it is gitignored, so an updater checkout could never update it — self-listing is meaningless and widens the never-touch set incorrectly).

Source

Thrown at update-system.mjs:486

/**
 * Read + validate the local declaration file.
 *
 * Refuses rather than honours anything ambiguous: a path the system layer
 * already ships would silently stop updating, and a path that escapes the
 * checkout would widen the "never touch" set over files the updater does not
 * own. Both throw, naming the offending entry.
 *
 * @param {string} [root=ROOT] - Repo root to read from.
 * @returns {string[]} Extra user-layer paths. Empty when the file is absent.
 */
export function localUserPaths(root = ROOT) {
  const file = join(root, LOCAL_PATHS_FILE);
  if (!existsSync(file)) return [];

  const declared = parseLocalPaths(readFileSync(file, 'utf-8'));
  const reject = (path, why) => {
    throw new Error(`${LOCAL_PATHS_FILE}: refusing "${path}" — ${why}`);
  };

  for (const path of declared) {
    if (path === LOCAL_PATHS_FILE) {
      reject(path, 'the declaration file cannot list itself (it is gitignored, so nothing updates it)');
    }
    if (path.startsWith('/') || /^[A-Za-z]:[\\/]/.test(path) || path.startsWith('\\')) {
      reject(path, 'paths must be repo-relative, not absolute');
    }
    if (path.split(/[\\/]/).includes('..')) {
      reject(path, 'paths must stay inside the repo');
    }
    const collision = SYSTEM_PATHS.find((sys) =>
      sys.endsWith('/') ? path.startsWith(sys) : path === sys,
    );
    if (collision) {
      reject(
        path,

View on GitHub (pinned to 60398d6549)

Solutions

  1. Use repo-relative paths: data/notes/ instead of /home/me/data/notes
  2. Remove .. segments — the file can only declare paths inside the repo
  3. Delete the self-referencing config/local-paths.txt line if present
  4. Re-run `node update-system.mjs check` (or apply) — the file is parsed on every update, so the fix takes effect immediately

Example fix

# before (config/local-paths.txt):
/home/me/career/notes
../shared-jds

# after:
data/notes/
jds-local/
Defensive patterns

Strategy: validation

Validate before calling

import { readFileSync } from 'fs';
const lines = readFileSync('config/local-paths.txt', 'utf-8').split('\n');
const bad = lines.map((s) => s.trim()).filter((p) => p && !p.startsWith('#') && (p.startsWith('/') || p.startsWith('\\') || /^[A-Za-z]:[\\/]/.test(p) || p.split(/[\\/]/).includes('..') || p === 'config/local-paths.txt'));
if (bad.length) throw new Error('invalid local-paths entries: ' + bad.join(', '));

Prevention

When it happens

Trigger: Pasting /home/me/notes or C:\cv\extra from a file dialog into config/local-paths.txt; adding ../shared-jds to protect files outside the repo; listing config/local-paths.txt as its own protected path.

Common situations: Users pasting OS-native absolute paths; trying to protect files that live outside the repository; copying example lines from docs that used absolute paths.

Related errors


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